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

Posted

技术标签:

【中文标题】如果 pthread_cond_signal 是线程中的最后一次调用,是不是存在数据竞争?【英文标题】:Is there a data race if pthread_cond_signal is the last call in a thread?如果 pthread_cond_signal 是线程中的最后一次调用,是否存在数据竞争? 【发布时间】:2017-11-15 13:21:11 【问题描述】:

-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_cond_signal 之后调用pthread_mutex_unlock,报告就会消失。但是手册上说pthread_cond_signal 不需要使用互斥锁。它是否记录在任何地方调用pthread_cond_signal 作为引用pthread_cond_t 的最后一个调用,并从执行pthread_cond_wait 的线程中销毁它是不合法的?

【问题讨论】:

在 C++ 中使用 std::thread。 【参考方案1】:

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

它们不能涵盖文档中的所有极端情况。是的,在互斥锁解锁后调用pthread_cond_signal()是合法的,在调用pthread_cond_signal()的同时销毁它是不合法的。

【讨论】:

【参考方案2】:

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

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

修复:

将连接移到两个“销毁”之前。

在您的示例中,我认为持有互斥锁的时间更长会防止这种情况发生,但我认为这对于大型软件来说不是一种可持续的方法。

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

【讨论】:

【参考方案3】:

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

所以你有两种可能。 要么在调用 pthread_cond_signal 时持有互斥锁,这样你的主线程在使用之前无法访问条件。 或者你可以先加入你的线程,然后破坏条件。两者都可以。

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

【讨论】:

以上是关于如果 pthread_cond_signal 是线程中的最后一次调用,是不是存在数据竞争?的主要内容,如果未能解决你的问题,请参考以下文章

Linux:pthread_cond_signal() 在 Signal Handler() 中不起作用

使用 pthread_cond_signal 的优雅线程终止证明有问题

pthread_cond_wait 丢失来自 pthread_cond_signal 的信号

条件变脸pthread_cond_signal丢失问题

perfreduce pthread_cond_signal via wait counter

pthread_cond_wait 和 pthread_cond_signal 的性能