首页 > 解决方案 > C 中的 volatile 是否安全/足够好,可以在没有共享数据时向另一个线程发出停止自身的信号?

问题描述

有许多资源可以解释为什么对于大多数多线程应用程序来说,单独使用 volatile 是不够的。

然而,仅仅用信号通知一个线程从另一个线程退出就足够了吗?在下面的示例中,主线程启动了第二个线程,一段时间后,它想要停止它。线程之间没有共享数据,也不需要线程返回代码,线程基本上只是用作附加硬件的保持活动触发器。

示例(为简洁起见省略了 thread_create 和 thread_join,它们基本上是 pthread_create 和 pthread_join 或 Windows 等效项的包装):

typedef struct {
    volatile bool keepRunning;
} ThreadContext;

static void thread(void *arg) {
  ThreadContext *context = (ThreadContext *)arg;
  while (context->keepRunning) {
    // do some fast operation
    // ...
    // then sleep before next iteration
    msleep(100);
  }
}

static int startThread(ThreadContext *context) {
  context->keepRunning = true;
  return thread_create(thread, context);
}

static void stopThread(ThreadContext *context) {
  context->keepRunning = false;
  thread_join();
}

static int main() {
  ThreadContext context;
  startThread(&context);
  msleep(10000);
  stopThread(&context);
}

编辑:我必须保持 Windows 兼容性并交叉编译到一些古老的工具链,所以 C11stdatomic.h不适用。如果有办法在 Windows 上使用常规条件变量,这可能是我可以尝试检查我的所有目标是否支持它们的一种方式。

EDIT2:另外,在这种情况下,我不关心事件的精确顺序,线程应该只最终停止(最多几次迭代之后),而不是永远等待加入,但它不必在之后立即停止设置标志,即如果线程再进行几次迭代,它不会造成任何伤害。

标签: c

解决方案


在大多数健全的架构和大多数健全的编译器上访问变量volatile bool都可以。但是,标准不保证这一点。

volatile sig_atomic_tPOSIX 标准保证对异步中断类型的安全访问。为了安全使用volatile sig_atomic_t。或者只是使用pthread_cond.

typedef struct {
    volatile sig_atomic_t keepRunning;
} ThreadContext;

在 C11 中,有一种方法可以检查访问bool是否是原子的并且不受中断影响,如果ATOMIC_BOOL_LOCK_FREEstdatomic.h.

一些参考资料:C11 草案 5.1.2.3p5posix signal.h


推荐阅读