I have worked the entire day on a c++ program and I can't find out what's missing. The problem is that I try to synchronize 2 programs with Mutex using winapi. I need to send random things from program1 to program2 using winapi file mapping but everytime I run it program1 writes in file mapping everything and after it runs every instance, program2 reads only the last number wrote in file mapping. There is no synchronize between these 2.
I need to open the second cpp program with CreateProcess function from the first program. I think that I don't release the mutex at the right time or I didn't start the second cpp file at the right time but everything I tried didn't work.
Here is the code:
Program1:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
int main()
{
//srand((unsigned int)time(NULL));
cout << "inside process 1" << endl;
HANDLE common_mutex = CreateMutex(
NULL, // default security attributes
TRUE, // initially not owned
"mainMutex"); // unnamed mutex
HANDLE create_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, 1024 * 1024, "data");
if (create_file_mapping_handle == NULL) {
printf("Cannot create file mapping. Error code: %d", GetLastError());
return 0;
}
unsigned char* pData = (unsigned char*)MapViewOfFile(create_file_mapping_handle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(create_file_mapping_handle);
return 0;
}
//create new process
PROCESS_INFORMATION process2;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess("C:\\Users\\raztu\\Desktop\\tema5to6CSSO\\process1\\Debug\\process2.exe", NULL,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &process2)) {
printf("Cannot create process.\n");
return 0;
}
for (int i = 0; i < 50; ++i) {
}
int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
common_mutex, // handle to mutex
INFINITE); // no time-out interval
if (dwWaitResult == WAIT_OBJECT_0) {
cout << "am intrat in sender process si scriu in file mapping" << endl;
RandomSum test;
DWORD randomNumber = rand() % 50;
test.a = randomNumber;
test.b = 2 * test.a;
memcpy(pData, &test, sizeof(RandomSum));
cout << "in process 1: " << "a = " << test.a << " b= " << test.b << endl;
}
ReleaseMutex(common_mutex);
cout << "last cout" << endl;
++counter;
}
CloseHandle(create_file_mapping_handle);
CloseHandle(common_mutex);
//getchar();
return 0;
}
Program2:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
int main()
{
cout << "inside process2" << endl;
//srand((unsigned int)time(NULL));
cout << "something new in process2" << endl;
LPCWSTR data = L"data";
HANDLE hData = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "data");
unsigned char* pData = (unsigned char*)MapViewOfFile(hData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(hData);
return 0;
}
HANDLE common_mutex = OpenMutex(
SYNCHRONIZE,
FALSE,
"mainMutex"
);
int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
common_mutex, // handle to mutex
INFINITE); // no time-out interval
if (dwWaitResult == WAIT_OBJECT_0) {
cout << "a inceput procesul 2" << endl;
RandomSum test;
memcpy(&test, pData, sizeof(RandomSum));
cout << "a is" << test.a << " and b is " << test.b << endl;
}
ReleaseMutex(common_mutex);
++counter;
}
CloseHandle(hData);
CloseHandle(common_mutex);
//getchar();
}
Could you tell me what's wrong?
You cannot use mutex to synchronize these two processes. The mutex released by program1 may be captured by program1 again.
everytime I run it program1 writes in file mapping everything and after it runs every instance, program2 reads only the last number wrote in file mapping.
It may be that the mutex of program1 release was always captured by program1 itself(100 times), and then captured by program2. One process need to notify the other process that it has finished writing/reading(with IPC). You can create 2 events and then use it to notify the other process in each process.
Program1:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
int main()
{
//srand((unsigned int)time(NULL));
cout << "inside process 1" << endl;
HANDLE hEvent1 = CreateEvent(NULL, FALSE, TRUE, "MyEvent1");
HANDLE hEvent2 = CreateEvent(NULL, FALSE, FALSE, "MyEvent2");
HANDLE create_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, 1024 * 1024, "data");
if (create_file_mapping_handle == NULL) {
printf("Cannot create file mapping. Error code: %d", GetLastError());
return 0;
}
unsigned char* pData = (unsigned char*)MapViewOfFile(create_file_mapping_handle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(create_file_mapping_handle);
return 0;
}
//create new process
PROCESS_INFORMATION process2;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess("C:\\path\\program2.exe", NULL,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &process2)) {
printf("Cannot create process.\n");
return 0;
}
CloseHandle(process2.hThread);
CloseHandle(process2.hProcess);
int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
hEvent1, // handle to mutex
INFINITE); // no time-out interval
if (dwWaitResult == WAIT_OBJECT_0) {
cout << "am intrat in sender process si scriu in file mapping" << endl;
RandomSum test;
DWORD randomNumber = rand() % 50;
test.a = randomNumber;
test.b = 2 * test.a;
memcpy(pData, &test, sizeof(RandomSum));
cout << "in process 1: " << "a = " << test.a << " b= " << test.b << endl;
cout << "last cout" << endl;
SetEvent(hEvent2);
}
++counter;
}
UnmapViewOfFile(pData);
CloseHandle(create_file_mapping_handle);
CloseHandle(hEvent1);
CloseHandle(hEvent2);
//getchar();
return 0;
}
Program2:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
int main()
{
cout << "inside process2" << endl;
//srand((unsigned int)time(NULL));
cout << "something new in process2" << endl;
HANDLE hEvent1 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, "MyEvent1");
HANDLE hEvent2 = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, "MyEvent2");
LPCWSTR data = L"data";
HANDLE hData = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "data");
unsigned char* pData = (unsigned char*)MapViewOfFile(hData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(hData);
return 0;
}
int counter = 0;
while (counter < 100) {
DWORD dwWaitResult = WaitForSingleObject(
hEvent2, // handle to mutex
INFINITE); // no time-out interval
if (dwWaitResult == WAIT_OBJECT_0) {
cout << "a inceput procesul 2" << endl;
RandomSum test;
memcpy(&test, pData, sizeof(RandomSum));
cout << "a is " << test.a << " and b is " << test.b << endl;
SetEvent(hEvent1);
}
++counter;
}
UnmapViewOfFile(pData);
CloseHandle(hData);
CloseHandle(hEvent1);
CloseHandle(hEvent2);
//getchar();
}
Or directly use the shared memory you are using for synchronization. Use the first byte of pdata
as a signal bit, and each process monitors whether it is its turn to execute.
Program1:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
BOOL WaitForProcess2(unsigned char* shared_address)
{
while (*shared_address != 1);//wait until the process1 set the first byte to 1;
return true;
}
int main()
{
//srand((unsigned int)time(NULL));
cout << "inside process 1" << endl;
HANDLE create_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, 1024 * 1024, "data");
if (create_file_mapping_handle == NULL) {
printf("Cannot create file mapping. Error code: %d", GetLastError());
return 0;
}
unsigned char* pData = (unsigned char*)MapViewOfFile(create_file_mapping_handle,
FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(create_file_mapping_handle);
return 0;
}
*pData = 1;
//create new process
PROCESS_INFORMATION process2;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess("C:\\path\\program2.exe", NULL,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &process2)) {
printf("Cannot create process.\n");
return 0;
}
CloseHandle(process2.hThread);
CloseHandle(process2.hProcess);
int counter = 0;
while (counter < 100) {
if (WaitForProcess2(pData)) {
cout << "am intrat in sender process si scriu in file mapping" << endl;
RandomSum test;
DWORD randomNumber = rand() % 50;
test.a = randomNumber;
test.b = 2 * test.a;
memcpy(pData+1, &test, sizeof(RandomSum)); //"pData + 1" skip the first signal bit
cout << "in process 1: " << "a = " << test.a << " b= " << test.b << endl;
cout << "last cout" << endl;
*pData = 2;
}
++counter;
}
UnmapViewOfFile(pData);
CloseHandle(create_file_mapping_handle);
//getchar();
return 0;
}
Program2:
#include <iostream>
#include <Windows.h>
#include <time.h>
using namespace std;
struct RandomSum {
DWORD a;
DWORD b;
};
BOOL WaitForProcess1(unsigned char* shared_address)
{
while (*shared_address != 2); //wait until the process1 set the first byte to 2;
return true;
}
int main()
{
cout << "inside process2" << endl;
//srand((unsigned int)time(NULL));
cout << "something new in process2" << endl;
LPCWSTR data = L"data";
HANDLE hData = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "data");
unsigned char* pData = (unsigned char*)MapViewOfFile(hData, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData == NULL) {
printf("Cannot get pointer to file mapping. Error code: %d", GetLastError());
CloseHandle(hData);
return 0;
}
int counter = 0;
while (counter < 100) {
if (WaitForProcess1(pData)) {
cout << "a inceput procesul 2" << endl;
RandomSum test;
memcpy(&test, pData + 1, sizeof(RandomSum)); //"pData + 1" skip the first signal bit
cout << "a is " << test.a << " and b is " << test.b << endl;
*pData = 1;
}
++counter;
}
UnmapViewOfFile(pData);
CloseHandle(hData);
//getchar();
}
In the end I used events just as you showed me. Thank you very much! The entire problem is clear to me now.