2010-10-29 30 views
0

我在理解winapi条件变量如何工作时遇到问题。在win32中使用条件变量API唤醒多个线程的问题

在更具体的一面,我想要的是一些等待一些条件的线程。然后,我想使用WakeAllConditionVariable()调用来唤醒所有线程,以便它们可以工作。除了我只想让线程开始的事实之外,他们没有任何其他先决条件可以开始工作(就像在n生产者/ n用户场景中那样)。

这里是到目前为止的代码:

#define MAX_THREADS 4 

CONDITION_VARIABLE start_condition; 
SRWLOCK   cond_rwlock; 
bool     wake_all; 

__int64 start_times[MAX_THREADS]; 

主线程:

int main() 
{ 
    HANDLE h_threads[ MAX_THREADS ]; 

    int tc; 
    for (tc = 0; tc < MAX_THREADS; tc++) 
    { 
     DWORD tid; 
     h_threads[tc] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)thread_routine,(void*)tc,0,&tid); 
     if(h_threads[tc] == NULL) 
     { 
      cout << "Error while creating thread with index " << tc << endl; 
      continue; 
     } 
    } 

    InitializeSRWLock(&cond_rwlock); 
    InitializeConditionVariable(&start_condition); 

    AcquireSRWLockExclusive(&cond_rwlock); 
     // set the flag to true, then wake all threads 
    wake_all = true; 
    WakeAllConditionVariable(&start_condition); 

    ReleaseSRWLockExclusive(&cond_rwlock); 

    WaitForMultipleObjects(tc, h_threads, TRUE, INFINITE); 

    return 0; 
} 

这里是线程程序的代码:

DWORD thread_routine(PVOID p_param) 
{ 
    int t_index = (int)(p_param); 

    AcquireSRWLockShared(&cond_rwlock); 

     // main thread sets wake_all to true and calls WakeAllConditionVariable() 
     // so this thread should start doing the work (?) 
    while (!wake_all) 
     SleepConditionVariableSRW(&start_condition,&cond_rwlock, INFINITE,CONDITION_VARIABLE_LOCKMODE_SHARED); 

    QueryPerformanceCounter((LARGE_INTEGER*)&start_times[t_index]); 
     // do the actual thread related work here 

    return 0; 
} 

此代码不会做什么我希望它能做到。有时候只有一个线程完成工作,有时候只有两个或三个线程完成工作,但从来没有完成任何工作主函数永远不会通过WaitForMultipleObjects()调用。

我不完全确定我做错了什么,但我会假设一些同步问题?

任何帮助,将不胜感激。 (对不起,如果我重新发布旧主题不同的更衣:)

+0

您的代码中存在争用条件。如果其中一个线程在主线程获得独占锁之前获取共享锁,主线程将挂起在AcquireRWLockExclusive中。 – 2011-08-28 12:15:13

回答

4

您初始化cond_rwlock和start_condition变量为时已晚。将代码向上移动,之前您启动线程。线程可能会立即开始运行,特别是在多核机器上。

并测试api函数的返回值。你不知道为什么它不起作用,因为你从不检查失败。

+0

谢谢,这是做的伎俩,这是显而易见的,它应该有.. – redeye 2010-10-29 17:29:14

+0

我最初创建的线程与CREATE_SUSPENDED标志,然后调用ResumeThread _after_初始化代码。当我改变CreateThread调用来创建它们以便它们立即启动时,我忘了移动到也移动条件init代码。我的错 :) – redeye 2010-10-29 17:31:39