Hi folks,

I am learning Thread syncronization. I have written a program for Win32 platform. This program creates two secondary threads from the primary thread. One thread is the "Even number writing thread" and the other is the "Odd number writing thread"

I have used a Mutex object for synchronising the two threads. Each thread must write its counter and give up the mutex.

Please let me know if I have implemented this problem correctly.

Thanks in advance,

Cheers,
Passionate_Guy

Code:
#include <stdio.h>
#include <windows.h>

#define MAX_THREADS 2
#define MAX_COUNTER 10 //must be even!!!

typedef struct struct_ThreadSharedData
{
    FILE *fp;
    int counter;
    HANDLE hMutex;
}ThreadSharedData;

typedef enum
{
    eERRCode_CouldNotOpenFileForWriting = 1,        //ERROR: could not open file for writing
    eERRCode_CouldNotOpenCreateMutexObject,         //ERROR: could not create Mutex Object
    eERRCode_CouldNotCloseFileAfterWorking,         //ERROR: could not close file after operation
    eERRCode_CouldNotReleaseMutex,                  //ERROR: could not Release Mutex.
    eERRCode_CouldNotObtaineMutexTillInfiniteTime,  //ERROR: could not Obtain Mutex till INFINITE timeout.

    eERRCode_MAXCODE
}eERRCODES;


int ERROR_EXIT(ThreadSharedData **pSharedData, eERRCODES err)
{
    //free the Shared Data variable allocated on the heap
    free(*pSharedData);

    (*pSharedData) = NULL;

    return err;
}


DWORD WINAPI OddWritingThread(void* pData)
{
    DWORD dwWaitResult;
    ThreadSharedData *pSharedData = (ThreadSharedData *)pData;

    while(pSharedData->counter != (MAX_COUNTER -1) )
    {
        // Request ownership of mutex.
        dwWaitResult = WaitForSingleObject(
                                            pSharedData->hMutex,    // handle to mutex
                                            INFINITE);              // Infinite time-out interval
        switch(dwWaitResult)
        {
        case WAIT_OBJECT_0:// The thread got mutex ownership.
            {
                
                if( (pSharedData->counter % 2) == 0 ) //enter only if the counter is an even integer
                {
                    (pSharedData->counter)++;
                    if(pSharedData->counter <= (MAX_COUNTER -1) )
                    {
                        //update the file
                        fprintf( pSharedData->fp, "%d\n", pSharedData->counter );
                    }
                }

                // Release ownership of the mutex object.
                if (! ReleaseMutex(pSharedData->hMutex)) 
                {
                    return ERROR_EXIT(&pSharedData, eERRCode_CouldNotReleaseMutex);
                }
            }
            break;

        case WAIT_ABANDONED:// Got ownership of the abandoned mutex object.
            break;

        case WAIT_TIMEOUT:// Cannot get mutex ownership due to time-out.
            {
                    return ERROR_EXIT(&pSharedData, eERRCode_CouldNotObtaineMutexTillInfiniteTime);
            }
            break;

        default:
            break;
        }
    }

    return 0;
}

DWORD WINAPI EvenWritingThread(void* pData)
{
    DWORD dwWaitResult;
    ThreadSharedData *pSharedData = (ThreadSharedData *)pData;



    while(pSharedData->counter != MAX_COUNTER )
    {
        // Request ownership of mutex.
        dwWaitResult = WaitForSingleObject(
                                            pSharedData->hMutex,    // handle to mutex
                                            INFINITE);              // Infinite time-out interval
        switch(dwWaitResult)
        {
        case WAIT_OBJECT_0:// The thread got mutex ownership.
            {
                if( (pSharedData->counter % 2) == 1 ) //enter only if the counter is an ODD integer
                {
                    (pSharedData->counter)++;
                    if(pSharedData->counter <= MAX_COUNTER )
                    {
                        //update the file
                        fprintf( pSharedData->fp, "%d\n", pSharedData->counter );
                    }
                }

                // Release ownership of the mutex object.
                if (! ReleaseMutex(pSharedData->hMutex)) 
                {
                    return ERROR_EXIT(&pSharedData, eERRCode_CouldNotReleaseMutex);
                }
            }
            break;

        case WAIT_ABANDONED:// Got ownership of the abandoned mutex object.
            break;

        case WAIT_TIMEOUT:// Cannot get mutex ownership due to time-out.
            {
                    return ERROR_EXIT(&pSharedData, eERRCode_CouldNotObtaineMutexTillInfiniteTime);
            }
            break;

        default:
            break;
        }

    }
    

    return 0;
}

int main(void)
{
    DWORD dwThreadId[MAX_THREADS];  //array to hold Thread identifiers
    HANDLE hThread[MAX_THREADS];    //array to hold Thread handles
    ThreadSharedData *pSharedData = NULL;

    pSharedData = (ThreadSharedData*) calloc(1,sizeof(ThreadSharedData));

    pSharedData->fp = fopen("file.txt","w");
    if(pSharedData->fp == NULL)
    {
        return ERROR_EXIT(&pSharedData, eERRCode_CouldNotOpenFileForWriting);
    }

    pSharedData->counter = 0;
    
    // Create a mutex with no initial owner.
    pSharedData->hMutex = CreateMutex(
                                        NULL,                           // no security attributes
                                        FALSE,                          // initially not owned
                                        "MutexToProtectFileAccess");    // name of mutex
    
    if (pSharedData->hMutex == NULL)
    {
         return ERROR_EXIT(&pSharedData, eERRCode_CouldNotOpenCreateMutexObject);
    }


    fprintf( pSharedData->fp, "\t\tThis file is written by two Threads.\n\n");
    fprintf( pSharedData->fp, "%d\n", pSharedData->counter );
    
    hThread[0] = CreateThread(
                                NULL,               // default security attributes
                                0,                  // use default stack size
                                EvenWritingThread,  // thread function 
                                (void*)pSharedData, // argument to thread function 
                                0,                  // use default creation flags 
                                &dwThreadId[0]);    // returns the thread identifier 
        
    // Check the return value for success.
    if (hThread[0] == NULL)
    {
        ExitProcess(0);
    }
    
    hThread[1] = CreateThread(
                                NULL,               // default security attributes
                                0,                  // use default stack size
                                OddWritingThread,   // thread function 
                                (void*)pSharedData, // argument to thread function 
                                0,                  // use default creation flags 
                                &dwThreadId[1]);    // returns the thread identifier 
        
    // Check the return value for success.
    if (hThread[1] == NULL)
    {
        ExitProcess(1);
    }

   // Wait until all threads have terminated.
    WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE);

    // Close all thread handles upon completion.
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);

    if( fclose(pSharedData->fp))
    {
        return ERROR_EXIT(&pSharedData, eERRCode_CouldNotCloseFileAfterWorking);
    }

    //free the Shared Data variable allocated on the heap
    free(pSharedData);
    pSharedData = NULL;

    return 0; //ALL_OK!!
}