Windows线程同步

来源:互联网 发布:javascript读取excel文件 编辑:程序博客网 时间:2024/06/04 19:00

以下内容摘抄自《Visual C++开发技术大全》,为学习笔记。

        线程同步的方法有很多,最常用的有 

互斥(CMutex)

临界(CriticalSection)

信号量(Semaphore)

事件(Event)等。

        这4种方式分别在 Win32 和 MFC 两种方式下各有一种实现, MFC 方式是对 Win32方式的封装,使用起来更加简便。

        互斥(CMutex)就是一个线程对共享资源进行访问时排斥其他的线程。互斥对象可通过CreateMutex 函数创建,在程序运行时只有拥有互斥对象的线程有访问共享资源的权利。如果线程对共享资源使用完了,要用ReleaseMutex 函数交出互斥对象,好让其他线程拥有对共享资源的访问权利。

#include <windows.h>#include <stdio.h>#define THREADCOUNT 2HANDLE ghMutex; DWORD WINAPI WriteToDatabase( LPVOID );int main( void ){    HANDLE aThread[THREADCOUNT];    DWORD ThreadID;    int i;    // Create a mutex with no initial owner    ghMutex = CreateMutex(         NULL,              // default security attributes        FALSE,             // initially not owned        NULL);             // unnamed mutex    if (ghMutex == NULL)     {        printf("CreateMutex error: %d\n", GetLastError());        return 1;    }    // Create worker threads    for( i=0; i < THREADCOUNT; i++ )    {        aThread[i] = CreateThread(                      NULL,       // default security attributes                     0,          // default stack size                     (LPTHREAD_START_ROUTINE) WriteToDatabase,                      NULL,       // no thread function arguments                     0,          // default creation flags                     &ThreadID); // receive thread identifier        if( aThread[i] == NULL )        {            printf("CreateThread error: %d\n", GetLastError());            return 1;        }    }    // Wait for all threads to terminate    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);    // Close thread and mutex handles    for( i=0; i < THREADCOUNT; i++ )        CloseHandle(aThread[i]);    CloseHandle(ghMutex);    return 0;}DWORD WINAPI WriteToDatabase( LPVOID lpParam ){     // lpParam not used in this example    UNREFERENCED_PARAMETER(lpParam);    DWORD dwCount=0, dwWaitResult;     // Request ownership of mutex.    while( dwCount < 20 )    {         dwWaitResult = WaitForSingleObject(             ghMutex,    // handle to mutex            INFINITE);  // no time-out interval         switch (dwWaitResult)         {            // The thread got ownership of the mutex            case WAIT_OBJECT_0:                 __try {                     // TODO: Write to the database                    printf("Thread %d writing to database...\n",                             GetCurrentThreadId());                    dwCount++;                }                 __finally {                     // Release ownership of the mutex object                    if (! ReleaseMutex(ghMutex))                     {                         // Handle error.                    }                 }                 break;             // The thread got ownership of an abandoned mutex            // The database is in an indeterminate state            case WAIT_ABANDONED:                 return FALSE;         }    }    return TRUE; }
        信号量允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目,超出这个最大数的线程将不允许访问此资源。主要通过CreateSemaphore 函数来实现。

HANDLE WINAPI CreateSemaphore(  _In_opt_  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  _In_      LONG lInitialCount,  _In_      LONG lMaximumCount,  _In_opt_  LPCTSTR lpName);
返回值:成功返回信号量句柄,失败返回 NULL;

参数: lpSemaphoreAttributes   安全属性

            lInitialCount                    正在运行线程的数量

            lMaximumCount              允许的最大数量

            lpName                           信号量名称

从函数原型可以看出,创建信号量时需要指出允许的最大资源计数和当前可用资源计数,每增加一个访问共享资源的线程,当前可以资源计数就减一。

#include <windows.h>#include <stdio.h>#define MAX_SEM_COUNT 10#define THREADCOUNT 12HANDLE ghSemaphore;DWORD WINAPI ThreadProc( LPVOID );int main( void ){    HANDLE aThread[THREADCOUNT];    DWORD ThreadID;    int i;    // Create a semaphore with initial and max counts of MAX_SEM_COUNT    ghSemaphore = CreateSemaphore(         NULL,           // default security attributes        MAX_SEM_COUNT,  // initial count        MAX_SEM_COUNT,  // maximum count        NULL);          // unnamed semaphore    if (ghSemaphore == NULL)     {        printf("CreateSemaphore error: %d\n", GetLastError());        return 1;    }    // Create worker threads    for( i=0; i < THREADCOUNT; i++ )    {        aThread[i] = CreateThread(                      NULL,       // default security attributes                     0,          // default stack size                     (LPTHREAD_START_ROUTINE) ThreadProc,                      NULL,       // no thread function arguments                     0,          // default creation flags                     &ThreadID); // receive thread identifier        if( aThread[i] == NULL )        {            printf("CreateThread error: %d\n", GetLastError());            return 1;        }    }    // Wait for all threads to terminate    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);    // Close thread and semaphore handles    for( i=0; i < THREADCOUNT; i++ )        CloseHandle(aThread[i]);    CloseHandle(ghSemaphore);    return 0;}DWORD WINAPI ThreadProc( LPVOID lpParam ){    // lpParam not used in this example    UNREFERENCED_PARAMETER(lpParam);    DWORD dwWaitResult;     BOOL bContinue=TRUE;    while(bContinue)    {        // Try to enter the semaphore gate.        dwWaitResult = WaitForSingleObject(             ghSemaphore,   // handle to semaphore            0L);           // zero-second time-out interval        switch (dwWaitResult)         {             // The semaphore object was signaled.            case WAIT_OBJECT_0:                 // TODO: Perform task                printf("Thread %d: wait succeeded\n", GetCurrentThreadId());                bContinue=FALSE;                            // Simulate thread spending time on task                Sleep(5);                // Release the semaphore when task is finished                if (!ReleaseSemaphore(                         ghSemaphore,  // handle to semaphore                        1,            // increase count by one                        NULL) )       // not interested in previous count                {                    printf("ReleaseSemaphore error: %d\n", GetLastError());                }                break;             // The semaphore was nonsignaled, so a time-out occurred.            case WAIT_TIMEOUT:                 printf("Thread %d: wait timed out\n", GetCurrentThreadId());                break;         }    }    return TRUE;}
        用事件 (Event)来实现线程的同步和互斥很相似。SetEvent可以看做是对某项特定任务完成的通知,先用CreateEvent 函数创建一个事件句柄,然后启动使用 WaitForSingleObject 函数来等待事件发生。

#include <windows.h>#include <stdio.h>#define THREADCOUNT 4 HANDLE ghWriteEvent; HANDLE ghThreads[THREADCOUNT];DWORD WINAPI ThreadProc(LPVOID);void CreateEventsAndThreads(void) {    int i;     DWORD dwThreadID;     // Create a manual-reset event object. The write thread sets this    // object to the signaled state when it finishes writing to a     // shared buffer.     ghWriteEvent = CreateEvent(         NULL,               // default security attributes        TRUE,               // manual-reset event        FALSE,              // initial state is nonsignaled        TEXT("WriteEvent")  // object name        );     if (ghWriteEvent == NULL)     {         printf("CreateEvent failed (%d)\n", GetLastError());        return;    }    // Create multiple threads to read from the buffer.    for(i = 0; i < THREADCOUNT; i++)     {        // TODO: More complex scenarios may require use of a parameter        //   to the thread procedure, such as an event per thread to          //   be used for synchronization.        ghThreads[i] = CreateThread(            NULL,              // default security            0,                 // default stack size            ThreadProc,        // name of the thread function            NULL,              // no thread parameters            0,                 // default startup flags            &dwThreadID);         if (ghThreads[i] == NULL)         {            printf("CreateThread failed (%d)\n", GetLastError());            return;        }    }}void WriteToBuffer(VOID) {    // TODO: Write to the shared buffer.        printf("Main thread writing to the shared buffer...\n");    // Set ghWriteEvent to signaled    if (! SetEvent(ghWriteEvent) )     {        printf("SetEvent failed (%d)\n", GetLastError());        return;    }}void CloseEvents(){    // Close all event handles (currently, only one global handle).        CloseHandle(ghWriteEvent);}int main( void ){    DWORD dwWaitResult;    // TODO: Create the shared buffer    // Create events and THREADCOUNT threads to read from the buffer    CreateEventsAndThreads();    // At this point, the reader threads have started and are most    // likely waiting for the global event to be signaled. However,     // it is safe to write to the buffer because the event is a     // manual-reset event.        WriteToBuffer();    printf("Main thread waiting for threads to exit...\n");    // The handle for each thread is signaled when the thread is    // terminated.    dwWaitResult = WaitForMultipleObjects(        THREADCOUNT,   // number of handles in array        ghThreads,     // array of thread handles        TRUE,          // wait until all are signaled        INFINITE);    switch (dwWaitResult)     {        // All thread objects were signaled        case WAIT_OBJECT_0:             printf("All threads ended, cleaning up for application exit...\n");            break;        // An error occurred        default:             printf("WaitForMultipleObjects failed (%d)\n", GetLastError());            return 1;    }                 // Close the events to clean up    CloseEvents();    return 0;}DWORD WINAPI ThreadProc(LPVOID lpParam) {    // lpParam not used in this example.    UNREFERENCED_PARAMETER(lpParam);    DWORD dwWaitResult;    printf("Thread %d waiting for write event...\n", GetCurrentThreadId());        dwWaitResult = WaitForSingleObject(         ghWriteEvent, // event handle        INFINITE);    // indefinite wait    switch (dwWaitResult)     {        // Event object was signaled        case WAIT_OBJECT_0:             //            // TODO: Read from the shared buffer            //            printf("Thread %d reading from buffer\n",                    GetCurrentThreadId());            break;         // An error occurred        default:             printf("Wait error (%d)\n", GetLastError());             return 0;     }    // Now that we are done reading the buffer, we could use another    // event to signal that this thread is no longer reading. This    // example simply uses the thread handle for synchronization (the    // handle is signaled when the thread terminates.)    printf("Thread %d exiting\n", GetCurrentThreadId());    return 1;}


        

0 0
原创粉丝点击