1

以下是我对SleepConditionVariableCS,WakeAllConditionVariable和线程创建函数的实现。问题是,有时当我尝试创建线程时,创建线程会卡WaitForSingleObject( cv->mut, INFINITE );SleepConditionVariableCS. 我无法弄清楚这里的比赛条件是什么。


typedef struct
{
  int waiters_count;
  HANDLE sema_;
  HANDLE mut;
} CONDITION_VARIABLE;

void SleepConditionVariableCS(CONDITION_VARIABLE *cv, CRITICAL_SECTION *cs, int32_t dwMilliseconds){
    WaitForSingleObject( cv->mut, INFINITE ); //Acuire object lock

    cv->waiters_count++;
    LeaveCriticalSection (cs);
    if (SignalObjectAndWait(cv->mut, cv->sema_, dwMilliseconds, FALSE) == WAIT_TIMEOUT){ //SignalObjectAndWait releases the lock
        cv->waiters_count--;
    }
    EnterCriticalSection(cs);
}

void WakeAllConditionVariable(CONDITION_VARIABLE *cv){
    WaitForSingleObject( cv->mut, INFINITE );

    while (cv->waiters_count > 0){
        cv->waiters_count = cv->waiters_count - 1;
        ReleaseSemaphore (cv->sema_, 1, 0);
    }
    ReleaseMutex(cv->mut);
}

void KernelThread_CreationWait(void *kthread){
    KernelThread *thread =  (KernelThread *) kthread;

    EnterCriticalSection(thread->lock);
    thread->state = Thread_CREATED;

    WakeAllConditionVariable(thread->condition_variable);

    LeaveCriticalSection(thread->lock);
    KernelThread_main(kthread);
}

KernelThread* createKernelThread(){
    EventHandler_getHandler();

    unsigned long threadid;
    int t;
    void *hand;

    KernelThread *thread = KernelThread_malloc();
    EnterCriticalSection(thread->lock);
    thread->state = Thread_WAITINGFORCREATION;
    hand = CreateThread(NULL,
            0, // security, stack size
            (LPTHREAD_START_ROUTINE)&KernelThread_CreationWait, // start
            (void *)thread,
            0,
            &threadid); // param, creation flags, id
    if (hand == NULL){
        printf("ERROR: return handle from CreateThread() is NULL\n");
        exit(-1);
    }
    thread->thread = hand;
    thread->thread_id = threadid;

    SleepConditionVariableCS(thread->condition_variable,thread->lock,INFINITE);
    LeaveCriticalSection(thread->lock);

    return thread;
}

void InitializeConditionVariable (CONDITION_VARIABLE *cv){
    cv->waiters_count = 0;
    cv->sema_ = CreateSemaphore (NULL,       // no security
                                0,          // initially 0
                                0x7fffffff, // max count
                                NULL);      // unnamed
    cv->mut = CreateMutex(
          NULL,              // default security attributes
          FALSE,             // initially not owned
          NULL);             // unnamed mutex
}
4

2 回答 2

1

在尝试使用 win32 api 实现 pthread 样式的条件变量时,请查看以下对陷阱的非常详细的分析。http://www.cs.wustl.edu/~schmidt/win32-cv-1.html。(特别是第 3.4 节)。

在您的代码中,我目前只看到一个问题。在SleepConditionVariableCS()

    LeaveCriticalSection (cs);
    if (SignalObjectAndWait(cv->mut, cv->sema_, dwMilliseconds, FALSE) == WAIT_TIMEOUT){ //SignalObjectAndWait releases the lock
        // RIGHT HERE YOU HAVE NOT ACQUIRED cv->mut
        cv->waiters_count--; // SO THIS IS A DATA RACE (with the cv->waiters_count uses in WakeAllConditionVariable()
    }
于 2013-04-08T21:52:34.480 回答
0

我没有发现任何对我来说真正突出的逻辑缺陷。

然而...

您是否在使用之前将 CONDITION_VARIABLE 初始化为已知状态?

您不会检查一些系统调用的返回,这些系统调用可能会返回您永远不会看到的错误。 WaitForSingleObject并且EnterCriticalSection 可能会失败或处理不当。

thread->lock在处理条件变量时,您是否总是锁定并保持锁定状态?我看到 2 段不同的代码引用thread->lock.

您是否每次都以相同的顺序锁定/解锁关键部分和 sem?

于 2013-04-08T21:19:04.913 回答