Warm tip: This article is reproduced from serverfault.com, please click

ReleaseMutex at the wrong time and the programs don't synchronize winapi

发布于 2020-11-30 17:17:28

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?

Questioner
JohnMat
Viewed
0
Drake Wu 2020-12-01 11:15:37

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();
}