如果pthread_cond_signal是线程中的最后一次调用,是否存在数据竞争?

时间:2017-11-15 13:21:11

标签: c++ multithreading synchronization posix

使用-fsanitize=thread进行汇总会产生pthread_cond_signalpthread_cond_destroy之间的数据竞赛报告:

#include <stdio.h>
#include <pthread.h>
#include <err.h>

bool done = false;

pthread_mutex_t mutex;
pthread_cond_t cond;

void *func(void *)
{   
    pthread_mutex_lock(&mutex);

    done = true;

    pthread_mutex_unlock(&mutex);

    pthread_cond_signal(&cond);

    return NULL;
}

int main()
{
    pthread_t thread;

    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);

    if (pthread_create(&thread, NULL, func, NULL) != 0)
        err(1, "pthread_create()");

    pthread_mutex_lock(&mutex);

    while (!done)
        pthread_cond_wait(&cond, &mutex);

    pthread_mutex_unlock(&mutex);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    pthread_join(thread, NULL);

    return 0;
}

如果我在pthread_mutex_unlock之后致电pthread_cond_signal,报告就会消失。但是手册说pthread_cond_signal不需要使用互斥锁。是否记录了调用pthread_cond_signal作为引用pthread_cond_t的最后一个调用的任何地方,并且从pthread_cond_wait的线程中销毁它是不合法的?

3 个答案:

答案 0 :(得分:1)

  

是否记录了调用pthread_cond_signal作为引用pthread_cond_t的最后一个调用的任何地方,并且从执行pthread_cond_wait的线程中销毁它是不合法的?

它们无法涵盖文档中的所有案例。是的,在互斥锁解锁后调用pthread_cond_signal()是合法的,在可以调用pthread_cond_signal()的同时销毁它是不合法的。

答案 1 :(得分:1)

在加入可能仍然使用它的线程之前销毁条件变量和互斥锁是个坏主意。请考虑以下情况:

  1. Main创建线程并被中断。
  2. func()一直运行到pthread_mutex_unlock,但在发出信号之前就会中断。
  3. main继续,done为真,所以它永远不会等待,解锁互斥锁并销毁条件变量,然后等待线程退出。
  4. func()在销毁的条件变量上调用pthread_cond_signal - 可能是一个坏主意。
  5. 修正:

    在两个“破坏”之前移动联接。

    在您的示例中,我认为持有互斥锁可以防止这种情况发生,但我认为对于大型软件而言,这不是一种可持续的方法。

    我不建议在绝对明显之前销毁任何同步对象(互斥,条件等),所有应该使用它们的线程都被连接或者由其他显式同步保证永远不会访问同步对象试。

答案 2 :(得分:0)

pthread_cond_signal作为最后一次通话是完全合法的。 并且还不需要为pthread_cond_signal保留互斥量 但在您的情况下,如果您不这样做,则可能会创建数据竞争。这是非法的 在您的情况下,当您的线程解锁互斥锁时,您的主线程可能会开始运行并破坏该情况。这是你的数据竞赛。

所以你有两种可能性 您在调用pthread_cond_signal时持有互斥锁,以便主线程在使用之前无法访问该条件。
或者你可以先加入你的线程,然后销毁这个条件。两者都有效。

但总的来说,我建议坚持std::threadstd::mutexstd::condition_variable