线程的同步与互斥

本文介绍了Windows环境下多线程程序设计中的线程等待机制,包括Sleep(), busyloop, WaitForSingleObject() 和 WaitForMultipleObjects() 的使用方法及示例代码。

一. 一般等待

1. sleep()

在操作系统中止此线程动作,直到渡过某个时间之后才恢复。

  1. VOID Sleep(  
  2.   DWORD dwMilliseconds   // sleep time  
  3. );  
VOID Sleep(
  DWORD dwMilliseconds   // sleep time
);

实际上你不可能事先知道什么事情要等待多久,比如一个高优先级线程抢占执行的话,这个时间将变得不可预测。

要注意的是,Sleep( ),会放弃系统分配的剩余的时间片,这样 OS 就能更好的服务其他的进程和线程了。

2. busy loop

  1. for (;;)  
  2. {  
  3.     GetExitCodeThread(hThrd1, &exitCode1);  
  4.       
  5.     if ( exitCode1 == STILL_ACTIVE )  
  6.         puts("Thread 1 is still running!");  
  7. }  
for (;;)
{
    GetExitCodeThread(hThrd1, &exitCode1);
    
    if ( exitCode1 == STILL_ACTIVE )
        puts("Thread 1 is still running!");
}

忙等,是很浪费CPU时间的!因为 for( ) 在一直工作。

二. 等待线程结束

  1. //等待一个线程结束  
  2. DWORD WaitForSingleObject(  
  3.   HANDLE hHandle,        // handle to object  
  4.   DWORD dwMilliseconds   // 最长的等待时间,INFINITE 表示无穷等待  
  5. );  
  6. // 返回值:  
  7. // WAIT_FAILED,    表示函数失败  
  8. // WAIT_OBJECT_0,    表示等待的核心对象变成激发状态  
  9. // WAIT_TIMEOUT,    表示核心对象在变成激发状态之前,时间终了了  
  10.   
  11.   
  12. //等待多个线程结束  
  13. DWORD WaitForMultipleObjects(  
  14.   DWORD nCount,             // handles 数组元素个数  
  15.   CONST HANDLE *lpHandles,  // handles 数组  
  16.   BOOL bWaitAll,            // TRUE 表示所有的handles都必须激发,此函数才得以返回  
  17.   DWORD dwMilliseconds      // 终了时间  
  18. );  
  19. // 返回值:  
  20. // WAIT_TIMEOUT,    时间终了  
  21. // WAIT_FAILED, 表示函数失败  
  22. // bWaitAA == TRUE, 返回值是 WAIT_OBJECT_0  
  23. // bWaitAA == FASLE,    返回值减去 WAIT_OBJECT_0,就表示数组中的哪一个 handle 被激发了  
  24. // WAIT_TIMEOUT,    表示核心对象在变成激发状态之前,时间终了了  
//等待一个线程结束
DWORD WaitForSingleObject(
  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds   // 最长的等待时间,INFINITE 表示无穷等待
);
// 返回值:
// WAIT_FAILED,    表示函数失败
// WAIT_OBJECT_0,    表示等待的核心对象变成激发状态
// WAIT_TIMEOUT,    表示核心对象在变成激发状态之前,时间终了了


//等待多个线程结束
DWORD WaitForMultipleObjects(
  DWORD nCount,             // handles 数组元素个数
  CONST HANDLE *lpHandles,  // handles 数组
  BOOL bWaitAll,            // TRUE 表示所有的handles都必须激发,此函数才得以返回
  DWORD dwMilliseconds      // 终了时间
);
// 返回值:
// WAIT_TIMEOUT,	时间终了
// WAIT_FAILED,	表示函数失败
// bWaitAA == TRUE,	返回值是 WAIT_OBJECT_0
// bWaitAA == FASLE,	返回值减去 WAIT_OBJECT_0,就表示数组中的哪一个 handle 被激发了
// WAIT_TIMEOUT,	表示核心对象在变成激发状态之前,时间终了了

说明:

WaitForXXXObject( ),相当于一个新版的 sleep( ),它能够在某个线程结束时被调用。

WaitForXXXObject( ),像 sleep( )一样,只会占用很少的CPU,不会出现忙等现象,所以效率会高很多。

WaitForXXXObject( ),到底在等什么?其实它等待的是一些对象被激发

三. 被激发对象

可被 WaitForXXXObject( )使用的核心对象有两种状态:激发与未激发,WaitForXXXObject( ) 在目标变成激发状态时才返回。

比如:

Thread 当线程结束时,线程对象即被激发

Process 当进程结束时,进程对象即被激发

Event 直接受控于 SetEvent(),PulseEvent(),ResetEvent()三个函数

Mutex 如果 mutex 没有被任何线程拥有,它就处于激发状态

Semaphore 当计数器内容大于0时,semaphore处于激发状态

当出现以上对象动作时,线程对象就会被激发,此时 WaitForXXXObject( ) 就能返回。

四. 示例代码

最多用三个线程来完成六项工作

  1. #define WIN32_LEAN_AND_MEAN  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <windows.h>  
  5.   
  6.   
  7. DWORD WINAPI ThreadFunc(LPVOID);  
  8.   
  9. #define THREAD_POOL_SIZE 3            //线程池大小为3  
  10. #define MAX_THREAD_INDEX THREAD_POOL_SIZE-1  
  11. #define NUM_TASKS 6                //共有6个任务  
  12.   
  13. int main()  
  14. {  
  15.     HANDLE  hThrds[THREAD_POOL_SIZE];  
  16.     int     slot = 0;  
  17.     DWORD   threadId;  
  18.     int     i;  
  19.     DWORD   rc;  
  20.   
  21.     for (i=1; i<=NUM_TASKS; i++)  
  22.     {  
  23.         /* 当用完线程池里所有的线程时,要等待其它线程结束 */  
  24.         if (i > THREAD_POOL_SIZE)  
  25.         {  
  26.             /* 等待一个线程结束 */  
  27.             rc = WaitForMultipleObjects(  
  28.                 THREAD_POOL_SIZE,  
  29.                 hThrds,  
  30.                 FALSE,  
  31.                 INFINITE );  
  32.             slot = rc - WAIT_OBJECT_0;  
  33.   
  34.             printf("Slot %d terminated\n", slot );  
  35.   
  36.             CloseHandle(hThrds[slot]);  
  37.         }  
  38.   
  39.         /* 创建 6 个线程 */  
  40.         hThrds[slot] = CreateThread(NULL,  
  41.             0,  
  42.             ThreadFunc,  
  43.             (LPVOID)slot,  
  44.             0,  
  45.             &threadId );  
  46.   
  47.         printf("Launched thread #%d (slot %d)\n", i, slot);  
  48.   
  49.         slot++;  
  50.     }  
  51.   
  52.     /* 等待所有的线程结束 */  
  53.     rc = WaitForMultipleObjects(  
  54.         THREAD_POOL_SIZE,  
  55.         hThrds,  
  56.         TRUE,  
  57.         INFINITE );  
  58.      
  59.     for (slot=0; slot<THREAD_POOL_SIZE; slot++)  
  60.         CloseHandle(hThrds[slot]);  
  61.   
  62.     printf("All slots terminated\n");  
  63.   
  64.     return EXIT_SUCCESS;  
  65. }  
  66.   
  67. /* 
  68.  * This function just calls Sleep for 
  69.  * a random amount of time, thereby 
  70.  * simulating some task that takes time. 
  71.  * 
  72.  * The param "n" is the index into 
  73.  * the handle array, kept for informational 
  74.  * purposes. 
  75.  */  
  76. DWORD WINAPI ThreadFunc(LPVOID n)  
  77. {  
  78.     srand( GetTickCount() );  
  79.   
  80.     Sleep((rand()%10)*800+500);  
  81.     printf("Slot %d idle\n", n);  
  82.       
  83.     return ((DWORD)n);  
  84. }  
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>


DWORD WINAPI ThreadFunc(LPVOID);

#define THREAD_POOL_SIZE 3            //线程池大小为3
#define MAX_THREAD_INDEX THREAD_POOL_SIZE-1
#define NUM_TASKS 6                //共有6个任务

int main()
{
    HANDLE  hThrds[THREAD_POOL_SIZE];
    int     slot = 0;
    DWORD   threadId;
    int     i;
    DWORD   rc;

    for (i=1; i<=NUM_TASKS; i++)
    {
        /* 当用完线程池里所有的线程时,要等待其它线程结束 */
        if (i > THREAD_POOL_SIZE)
        {
            /* 等待一个线程结束 */
            rc = WaitForMultipleObjects(
                THREAD_POOL_SIZE,
                hThrds,
                FALSE,
                INFINITE );
            slot = rc - WAIT_OBJECT_0;

            printf("Slot %d terminated\n", slot );

            CloseHandle(hThrds[slot]);
        }

        /* 创建 6 个线程 */
        hThrds[slot] = CreateThread(NULL,
            0,
            ThreadFunc,
            (LPVOID)slot,
            0,
            &threadId );

        printf("Launched thread #%d (slot %d)\n", i, slot);

        slot++;
    }

    /* 等待所有的线程结束 */
    rc = WaitForMultipleObjects(
        THREAD_POOL_SIZE,
        hThrds,
        TRUE,
        INFINITE );
   
    for (slot=0; slot<THREAD_POOL_SIZE; slot++)
        CloseHandle(hThrds[slot]);

    printf("All slots terminated\n");

    return EXIT_SUCCESS;
}

/*
 * This function just calls Sleep for
 * a random amount of time, thereby
 * simulating some task that takes time.
 *
 * The param "n" is the index into
 * the handle array, kept for informational
 * purposes.
 */
DWORD WINAPI ThreadFunc(LPVOID n)
{
    srand( GetTickCount() );

    Sleep((rand()%10)*800+500);
    printf("Slot %d idle\n", n);
    
    return ((DWORD)n);
}

说明:

代码是《Win32多线程程序设计》上的,很经典。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值