2

我有一个计数器变量,它将被多个线程访问,这些线程将递增/递减它。它不应该被多个线程同时更新。

我知道您可以创建一个互斥对象,必须在更改相关变量之前获取该对象。在这种情况下,临界区是不合适的,因为有超过 1 个函数可以更改相关变量。

有没有另一个我可以在不使用互斥锁的情况下做到这一点?使用互斥锁确实会降低性能(请参阅http://www.codeguru.com/forum/showthread.php?t=333192)。我相信在 Java 中,您可以在变量声明中使用一个关键字来完成此操作(是否称为“同步”?),但是在 C++ 中是否有这样的事情呢?

我知道 volatile 不是我要寻找的关键字。

非常感谢。

4

8 回答 8

8

大多数处理器都有“原子”递增和递减指令——在很大程度上,它们是在机器级别实现互斥锁的方式。

您可以在自己的代码中访问这些原子指令。Windows 提供了该InterlockedIncrement()功能,而glib 提供了等价物。在 x86 汇编语言中,可以LOCK CMPXCHG直接使用和 kin。

C++ 对这些概念一无所知——你必须自己使用它们;C++ 中没有用于线程安全的神奇关键字。

参见原子指令

于 2010-01-28T12:53:35.310 回答
4

虽然使用原子操作可能是最有效的,但在多个函数中使用 this 的事实并不妨碍在此代码或任何其他代码中使用关键部分 - 只需编写一个函数:

void IncDec( bool inc ) {
   EnterCritical Section( theCS );
   if ( inc ) {
     theVar++;
   }
   else {
     thevar--;
   }
   LeaveCriticalSection( theCS );
}

并从您的其他功能中调用它。

于 2010-01-28T12:59:45.967 回答
3

从描述中,听起来您可能只需要InterlockedIncrement和相关的递减函数。

编辑 - 这些是 Windows 功能......我没有停下来询问哪个平台。

于 2010-01-28T12:53:04.023 回答
3

在这种情况下,临界区是不合适的,因为有超过 1 个函数可以更改相关变量。

这是使用关键部分的常见场景,您需要确保访问变量的每一段代码在进入相同的关键部分(或互斥锁,或使用任何保护)时都这样做。

于 2010-01-28T13:01:24.237 回答
2

在 Win32 中,IntelockedIncrement/IntelockedIncrement64 和相关操作编译为 x86 指令,允许对 32 位或 64 位字(取决于您的体系结构)进行处理器级原子操作。这在简单计数器的情况下工作正常,但如果您尝试将更大的结构与多个单词同步,自然不会工作。

PS from here,您需要在 x86 上运行的非 Win32 系统上实现它的相应 asm。

inline long InterlockedExchangeAdd( long* Addend, long Increment )
{
long ret;
__asm__ (
/* lock for SMP systems */
"lock\n\t"
"xaddl %0,(%1)"
:"=r" (ret)
:"r" (Addend), "0" (Increment)
:"memory" );
return ret;
}

inline long InterlockedIncrement( long* Addend )
{
return InterlockedExchangeAdd( Addend, 1 );
}

inline long InterlockedDecrement( long* Addend )
{
return InterlockedExchangeAdd( Addend, -1 );
}
于 2010-01-28T12:59:15.910 回答
0

在这种情况下,临界区是不合适的,因为有超过 1 个函数可以更改相关变量。

如果您不使用关键部分创建单个函数来修改变量,您如何知道您已找到该变量可能访问的所有位置?

此外,您需要声明变量 volatile 以确保您的编译器不会无意中优化对变量的任何访问。

于 2010-01-28T14:36:27.103 回答
0

您可以对计数器变量使用原子类型 - 例如 sig_atomic_t (在 GNU libc 中)。那么就不需要同步了,因为竞态条件不会发生,所以对这个变量的操作保证是原子的。

于 2010-01-28T12:58:31.307 回答
0

正如其他人所提到的,当前的 C++ 标准中没有任何内容支持原子变量访问。但是,如果您要求 C++ 库支持(我并不完全清楚),这里正在尝试模仿即将到来的 C++ 标准的原子支持。

于 2010-01-28T14:19:41.750 回答