我用同一个线程函数启动多个线程,现在要完成这样的功能:for一个循环启动线程, 但是一次只运行一个线程实例,后续的线程处于等待状态,只有前面的线程执行完了,后面的线程才能执行请问大侠用WaitForSingleObject应该怎么做

解决方案 »

  1.   

    管理事件内核对象
      在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信,除此之外,事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下:// 事件句柄
    HANDLE hEvent = NULL;
    // 共享资源 
    char g_cArray[10];
    ……
    UINT ThreadProc12(LPVOID pParam)
    {
     // 等待事件置位
     WaitForSingleObject(hEvent, INFINITE);
     // 对共享资源进行写入操作
     for (int i = 0; i < 10; i++)
     {
      g_cArray[i] = 'a';
      Sleep(1);
     }
     // 处理完成后即将事件对象置位
     SetEvent(hEvent);
     return 0;
    }
    UINT ThreadProc13(LPVOID pParam)
    {
     // 等待事件置位
     WaitForSingleObject(hEvent, INFINITE);
     // 对共享资源进行写入操作
     for (int i = 0; i < 10; i++)
     {
      g_cArray[10 - i - 1] = 'b';
      Sleep(1);
     }
     // 处理完成后即将事件对象置位
     SetEvent(hEvent);
     return 0;
    }
    ……
    void CSample08View::OnEvent() 
    {
     // 创建事件
     hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
     // 事件置位
     SetEvent(hEvent);
     // 启动线程
     AfxBeginThread(ThreadProc12, NULL);
     AfxBeginThread(ThreadProc13, NULL);
     // 等待计算完毕
     Sleep(300);
     // 报告计算结果
     CString sResult = CString(g_cArray);
     AfxMessageBox(sResult);
    }   在创建线程前,首先创建一个可以自动复位的事件内核对象hEvent,而线程函数则通过WaitForSingleObject()等待函数无限等待hEvent的置位,只有在事件置位时WaitForSingleObject()才会返回,被保护的代码将得以执行。对于以自动复位方式创建的事件对象,在其置位后一被WaitForSingleObject()等待到就会立即复位,也就是说在执行ThreadProc12()中的受保护代码时,事件对象已经是复位状态的,这时即使有ThreadProc13()对CPU的抢占,也会由于WaitForSingleObject()没有hEvent的置位而不能继续执行,也就没有可能破坏受保护的共享资源。在ThreadProc12()中的处理完成后可以通过SetEvent()对hEvent的置位而允许ThreadProc13()对共享资源g_cArray的处理。这里SetEvent()所起的作用可以看作是对某项特定任务完成的通知。  使用临界区只能同步同一进程中的线程,而使用事件内核对象则可以对进程外的线程进行同步,其前提是得到对此事件对象的访问权。可以通过OpenEvent()函数获取得到,其函数原型为:HANDLE OpenEvent(
     DWORD dwDesiredAccess, // 访问标志
     BOOL bInheritHandle, // 继承标志
     LPCTSTR lpName // 指向事件对象名的指针
    );   如果事件对象已创建(在创建事件时需要指定事件名),函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象,可以通过使用内核对象的继承性或是调用DuplicateHandle()函数来调用CreateEvent()以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。  如果需要在一个线程中等待多个事件,则用WaitForMultipleObjects()来等待。WaitForMultipleObjects()与WaitForSingleObject()类似,同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权,任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects()的函数原型为:DWORD WaitForMultipleObjects(
     DWORD nCount, // 等待句柄数
     CONST HANDLE *lpHandles, // 句柄数组首地址
     BOOL fWaitAll, // 等待标志
     DWORD dwMilliseconds // 等待时间间隔
    );   参数nCount指定了要等待的内核对象的数目,存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject()中的作用是完全一致的。如果等待超时,函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值,则说明所有指定对象的状态均为已通知状态(当fWaitAll为TRUE时)或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引(当fWaitAll为FALSE时)。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间,则表示所有指定对象的状态均为已通知,且其中至少有一个对象是被丢弃的互斥对象(当fWaitAll为TRUE时),或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引(当fWaitAll为FALSE时)。 下面给出的代码主要展示了对WaitForMultipleObjects()函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出:// 存放事件句柄的数组
    HANDLE hEvents[2];
    UINT ThreadProc14(LPVOID pParam)

     // 等待开启事件
     DWORD dwRet1 = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
     // 如果开启事件到达则线程开始执行任务
     if (dwRet1 == WAIT_OBJECT_0)
     {
      AfxMessageBox("线程开始工作!");
      while (true)
      {
       for (int i = 0; i < 10000; i++);
       // 在任务处理过程中等待结束事件 
       DWORD dwRet2 = WaitForMultipleObjects(2, hEvents, FALSE, 0);
       // 如果结束事件置位则立即终止任务的执行
       if (dwRet2 == WAIT_OBJECT_0 + 1)
        break;
      }
     }
     AfxMessageBox("线程退出!");
     return 0;
    }
    ……
    void CSample08View::OnStartEvent() 
    {
     // 创建线程
     for (int i = 0; i < 2; i++)
      hEvents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
      // 开启线程
      AfxBeginThread(ThreadProc14, NULL);
      // 设置事件0(开启事件)
      SetEvent(hEvents[0]);
    }
    void CSample08View::OnEndevent() 
    {
     // 设置事件1(结束事件)
     SetEvent(hEvents[1]);

      

  2.   

    可以用内核事件Event来控制流程
    后面的线程WaitForSingleObject等待事件触发,只有前面的线程运行完了后,触发事件,从而开始后面的线程
      

  3.   

    you can use CRITICAL_SECTION to control this
      

  4.   

    to Pandona(我很想拜师呀) :多谢,你的方法好用to flyelf(空谷清音): 多线程是同时启动的,如果用CRITICAL_SECTION能保证第一个线程启动后
    第二个线程发送临界区被加了锁,就不启动了,这样不是就不符合我的要求,第二个线程等待第一个线程执行完毕再启动?