条件是一种特殊类型的锁,我们使用它来保证同步操作按顺序执行。它与互斥锁有点点不同。等待条件的线程会因此阻塞,直到另一个线程发出该条件所需的信号。

由于某些操作系统的实现方式不同,它们在设置条件时允许返回伪成功(也就是并不是真正意义上的成功),也就是说并没有实际发出信号。避免因为伪信号造成的问题,我们应该将条件和predicate结合起来使用。predicate是确保线程是否安全执行的具体方法。直到信号设置了predicate,便让线程从休眠状态(该状态由条件导致)唤醒。

4.7.1 使用NSCondition类

NSCondition类提供了和POSIX条件差不多意思的条件,但是已经将锁和所需的数据包装进了NSCondition对象中。结果是一个对象,但是可以想互斥锁一样锁定线程,然后像条件一样等到发出的特定条件信号。

/// 官方文档例子
[cocoaCondition lock];
while (timeToDoWork <= 0)
    [cocoaCondition wait];

timeToDoWork--;

// Do real work here.

[cocoaCondition unlock];

上诉代码中将等待NSCondition对象的事件被序列化,cocoaCondition变量包含了NSCondition对象,timeToDoWork变量是一个整型变量,用来通知在条件到达之前的线程增量。

下面的代码展示了Cocoa条件信号,增加predicate值。我们应该在发送信号之前锁定该条件

/// 官方文档例子
[cocoaCondition lock]; /// 在发送之前需要将条件锁定
timeToDoWork++;
[cocoaCondition signal];
[cocoaCondition unlock];

4.7.2 使用POSIX条件

POSIX线程条件锁必须要使用条件数据结构和互斥锁。尽管这两个锁结果是独立的,但是在runtime中互斥锁和条件是密切相关的。线程在等待信号时,总是同时使用相同的互斥锁和条件。改变这个组合可能会导致出现错误。

下面的代码展示了最基本的初始化及使用条件和predicate。在将条件和互斥锁初始完成之后,等到线程使用ready_to_go变量作为它进入循环的predicate。只有当设置了predicate,条件信号到来之后,等待线程才被唤醒并开始处理相关工作。

/// 官方例子
pthread_mutex_t mutex;
pthread_cond_t condition;
Boolean     ready_to_go = true;

void MyCondInitFunction()
{
    pthread_mutex_init(&mutex);
    pthread_cond_init(&condition, NULL);
}

void MyWaitOnConditionFunction()
{
    // Lock the mutex.
    pthread_mutex_lock(&mutex);

    // If the predicate is already set, then the while loop is bypassed;
    // otherwise, the thread sleeps until the predicate is set.
    while(ready_to_go == false)
    {
        pthread_cond_wait(&condition, &mutex);
    }

    // Do work. (The mutex should stay locked.)

    // Reset the predicate and release the mutex.
    ready_to_go = false;
    pthread_mutex_unlock(&mutex);
}

发出信号的线程需要设置predicate和发送信号给条件锁。下面代码实现这个功能,在这个例子中,在互斥体内部发出条件信号,防止在线程等待条件时发生竞争(the condition is signaled inside of the mutex to prevent race conditions from occurring between the threads waiting on the condition)(这句话没有读懂啊,是我翻译不对没有理解到意思吗)。

/// 官方例子
void SignalThreadUsingCondition()
{
    // At this point, there should be work for the other thread to do.
    pthread_mutex_lock(&mutex);
    ready_to_go = true;

    // Signal the other thread to begin work.
    pthread_cond_signal(&condition);

    pthread_mutex_unlock(&mutex);
}

本人总结TIPS

  • 发出信号的线程需要设置predicate和发送信号给条件锁

results matching ""

    No results matching ""