【问题标题】:pthreads / C : using a flag to gracefully terminate other threadspthreads / C : 使用标志优雅地终止其他线程
【发布时间】:2021-05-28 05:52:21
【问题描述】:

使用仅由一个线程编写并且仅由其他线程读取的标志来优雅地终止线程是否安全(并且是一种良好的做法)?

考虑以下代码:

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

static int run;
static pthread_t t1, t2;

static void *threadFunc(void *context)
{
    puts("thread starting");

    init();

    while(run)
    {
        do_stuff();
    }

    clean_up();

    puts("thread exiting");

    return NULL;
}

int main(int argc, char **argv)
{
    puts("program starting");
    run = 1;

    pthread_create(&t1, NULL, threadFunc, NULL);
    pthread_create(&t2, NULL, threadFunc, NULL);

    do_some_stuff();

    run = 0;

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    puts("program exiting");
    return 0;
}

变量“run”用于告诉线程 t1 和 t2 终止。那很好还是我应该使用互斥体/内存屏障?为什么? 我不在乎在线程退出之前是否需要更多的循环周期,但我不希望它们永远运行。 我不想使用 pthread_cancel(),因为我希望线程只有在完成主循环的一个循环后才退出。

谢谢

【问题讨论】:

    标签: c multithreading pthreads


    【解决方案1】:

    您需要一个互斥锁来保护共享变量,因为这是 pthreads 标准所说的。您不能假设它失败的最坏方式是“在线程退出之前再花几个循环周期”。

    它可能会崩溃。它可能无法停止。任何事情都有可能发生。

    如果您的平台支持某种原子类型或原子操作,您可以使用它。

    有些人认为将volatile 用于“关闭”标志是可以接受的。请注意,这是非常特定于平台的,可能适合您,也可能不适合您。我不认为它在有更好选择的平台上是可以接受的,也就是说,在所有现代平台上。

    【讨论】:

    • 那么在每次读取、每次循环以及写入时都获取互斥锁?
    • @user1472946 是的。如果您要使用互斥锁,那么您必须这样做。写入应该很少见,周期也应该相距很远。或者,每个现代平台都有某种原子操作或原子类型,可以避免额外的锁定/解锁。 (无论如何,非竞争互斥体几乎是免费的,)
    • 既然只有一个线程写入和两个读取,那么使用读写锁而不是互斥锁会更高效吗?
    • @user1472946 可能不会。锁只保持一瞬间,因此几乎没有争用可以最小化。读/写锁的额外开销不会产生任何好处。
    • 值得添加 volatile 告诉编译器变量引用的内存位置可能会在程序控制之外更改。这意味着编译器无法对内存地址的值做出假设并可能优化读取。所以 volatile 有点帮助。还需要一个数据存储屏障(假设数据类型小于字大小)。这将确保特定于核心的缓存将看到来自其他 CPU 的读取。原子和互斥体都确保发生这种情况。
    【解决方案2】:

    最安全的方法是使run 原子化。现代 C 确实支持原子类型。

    【讨论】:

    • 好的,但够了吗?
    • 应该是。典型的atomic 类型被定义为对并发修改和访问是安全的,并且通常保证更改将“很快”被其他线程看到。
    • sigatomic_t 够用还是我必须使用 C11 stdatomic?
    • sigatomic_t 用于信号而不是多线程
    • 好的,只需将运行类型从 int 更改为 atomic_int 就可以了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2015-06-07
    • 2012-03-16
    • 1970-01-01
    • 2016-05-31
    相关资源
    最近更新 更多