Windows 操作系统中的线程安全和原子读取

Posted

技术标签:

【中文标题】Windows 操作系统中的线程安全和原子读取【英文标题】:Thread-safety and atomic reading in Windows OS 【发布时间】:2011-02-04 12:46:27 【问题描述】:

我的应用程序中有这段代码。我怀疑它不是线程安全的,所以决定问问 SOers。

int * volatile int_ptr;
int count;

线程 1:

void grow(int new_count)

    if(new_count <= count) return;
    int * new_ptr = new int[new_count];
    memset(new_ptr, 0 , new_count * sizeof(int));
    memcpy(new_ptr,int_ptr,count);
    int * dum_ptr = (int *)InterlockedExchange((volatile long *)&int_ptr,(long)new_ptr)     
    count = new_count;
    delete [] dum_ptr;

线程 2:

int get_value(int index)

    return int_ptr[index];

我知道可以使用 CRITICAL_SECTION,但线程 1 可能一周工作一次,而线程 2 一天工作数百万次。在 99.99999% 的访问 int_ptr 的尝试中,第二个线程将无缘无故地进入和退出临界区。这对我来说没有意义。该应用程序只能在 Windows 2000 和更高版本中运行,并且显然具有多核英特尔处理器。

这段代码是线程安全的吗?如果不是,我应该怎么做才能使它成为线程安全的?如何以原子方式读取 int_ptr ?一世。 e. :

int * dummy_ptr = read_atomic<int *>(int_ptr);
return dummy_ptr[index];

一个解决方案,包括std::vector,让我更快乐、更舒服。

【问题讨论】:

volatile 在这里没有为你做任何事情 @John Dibling:严格来说是为了我的实现还是一般? 不是要拖钓,但如果您认为可以摆脱此代码,您的用户名是合适的。 :-) 两者,真的。 volatile 在多线程编程中毫无用处。见:***.com/questions/4557979/… 【参考方案1】:

不,这不安全。 get_value 可以读取int_ptr 的值,然后被调度出去。然后另一个线程可以换出 int_ptrdelete 旧值。当get_value 被换回时,它会尝试取消引用它从int_ptr 读取的值 - 该值已被删除。

更好的方法是基于"Read-copy-update" (RCU),它已经在Linux 中得到了很好的应用。基本原则是您不要立即删除旧值 - 您等到某个时间点可以保守地确定没有任何东西仍然具有旧指针值,然后将其删除。

很遗憾,Windows 上还没有 RCU 库实现。我想你可以尝试将urcu 移植到 Windows。

【讨论】:

【参考方案2】:

不,不是。一种情况是 thread2 在 get_value 函数内,并且正在执行 int_ptr[index]。由于它不是原子的,这可能需要几个指令。这些指令执行到一半时,发生线程上下文切换,thread1 开始以grow 执行。这将delete[]int_ptr。现在当 thread2 启动时,它会遇到访问冲突。您可以使用CCriticalSection 来解决这个问题。由于它不是内核对象,因此在 Windows 操作系统上性能还不错。

【讨论】:

CCriticalSection 有一个内置的 CRITICAL_SECTION 实现。你认为我没有 CRITICAL_SECTIONs 的替代品【参考方案3】:

考虑让线程 1 要求线程 2 执行更新或在执行更新时等待。

为了使这个有用,线程 2 必须侦听来自系统其余部分的某种信号或消息。可以使用新消息扩展消息传递机制或条件变量。还要考虑 APC(有点像 Unix 信号)。

这需要实际询问而不是强行暂停。强行挂起线程并不能解决问题,因为线程可能在任何时候挂起,包括在读取int_ptr 和读取int_ptr[index] 之间。

【讨论】:

以上是关于Windows 操作系统中的线程安全和原子读取的主要内容,如果未能解决你的问题,请参考以下文章

Java 高并发三 Java内存模型和线程安全详解

Java线程安全

Java进阶 线程安全

C++多线程

Java高并发-Java内存模型和线程安全

Java 并发编程线程简介 ( 原子操作 | volatile 关键字使用场景 )