2011-02-04 95 views
2

我在我的应用程序中有这段代码。我怀疑它不是线程安全的,所以决定询问SOers。在Windows操作系统中的线程安全和原子读取

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以及更高版本的Intel处理器上运行,显然是多核心处理器。

此代码是否线程安全?如果没有,我应该怎么做才能保证线程安全?我如何可以自动读取int_ptr?一世。即:

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

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

+1

`volatile`在这里对你没有任何帮助 – 2011-02-04 13:31:03

+0

@John Dibling:严格来说我的实施还是一般? – 2011-02-04 13:32:48

回答

7

不,这是不安全的。 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操作系统上的性能并不是很差。

0

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

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

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

相关问题