0

这个函数的命名似乎是一些复杂的事情。什么时候知道这是要走的路,而不是做这样的事情:

准备 CRITICAL_SECTION cs; int *p = malloc(sizeof(int)); // 分配站点 InitializeCriticalSection(&cs); // 第一次写入的提示

线程 #1 { *p = 1; // 先写 }

线程 #2 { EnterCriticalSection(&cs); *p = 2; // 第二次写入 LeaveCriticalSection(&cs); }

我有一个在一个线程中完成的写入:

Run()
{
// some code
m_bIsTerminated = TRUE;
// some more code
}

然后,我有一个在另一个线程中完成的读取(可能同时):

Terminate()
{
// some code
if( m_bIsTerminated )
{
m_dwThreadId = 0;
m_hThread = NULL;
m_evExit.SetEvent();
return;
}
// even more code
}

解决这种竞争条件的最佳解决方案是什么?关键部分是要走的路还是使用 InterlockedExchangeAdd() 更有用?

4

3 回答 3

3

在您的情况下,没有竞争条件。变量永远不会重置为 FALSE,是吗?这只是线程的“请死”开关,对吗?然后不需要任何形式的同步。

InterlockedXXX 系列函数利用 Intel CPU 的原子 3 操作数命令(XADD 和 CMPXCNG)。所以它们比临界区便宜得多。而你想要的线程安全分配是 InterlockedCompareExchange()。

UPD: 并将变量标记为 volatile。

于 2010-01-14T22:02:51.723 回答
0

确保 m_bIsTerminated 被标记为 volatile,你应该没问题。尽管在我看来,在将“终止”设置为 true 之后,您会 // ​​再添加一些代码。该变量究竟表明了什么?

您的“竞争条件”是 // 更多代码的各种元素可以以不同的顺序执行。你的变量没有帮助。您的目标是让它们以确定的顺序执行吗?如果是,您需要一个条件变量来等待一个线程并设置另一个线程。如果您只是不希望它们同时执行,那么关键部分就可以了。

于 2010-01-14T22:11:53.710 回答
0

InterlockedExchangeAdd 用于将值作为原子操作添加到整数,这意味着您不必使用临界区。如果您的一个线程抛出异常,这也消除了死锁的风险——您需要确保不保留任何类型的锁,因为这会阻止其他线程获取该锁。

对于您的场景,您绝对可以使用 Interlocked...- 函数,但我会使用一个事件(CreateEvent、SetEvent、WaitForSingleObject),可能是因为我经常发现自己需要等待多个对象(您可以等待零秒在您的情况下)。

更新:对变量使用 volatile 可能有效,但不建议这样做,请参阅:http ://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html和http://例如/www-949.ibm.com/software/rational/cafe/blogs/ccpp-parallel-multicore/tags/c%2B%2B0x

如果您想便携,请查看boost::thread

于 2010-01-14T22:17:15.233 回答