任何人都知道原始全局变量是否是线程安全的?
// global variable
int count = 0;
void thread1()
{
count++;
}
void thread2()
{
count--;
if (count == 0) print("Stuff thing");
}
我是否可以这样做而没有count
的任何锁定保护?
谢谢。
答案 0 :(得分:6)
这不是线程安全的。你这里有种族条件。原因是count++
不一定是原子的(意味着不是单个处理器操作)。首先加载该值,然后递增,然后写回。在每个步骤之间,另一个线程也可以修改该值。
答案 1 :(得分:3)
不,不是。它可能可能,取决于实现,编译时选项甚至是月相。
但是标准并没有强制要求某些东西是线程安全的,特别是因为在当前标准中没有任何线程。
另请参阅here以获取有关此类问题的更详细分析。
如果您正在使用支持线程的环境,则可以使用互斥锁:例如,检查POSIX线程下的pthread_mutex_*
调用。
如果您正在编写C ++ 0x / C ++ 11,请使用互斥锁或该标准中详述的原子操作之一。
答案 2 :(得分:0)
它是一个全局变量,因此多个线程可以竞争改变它。它不是线程安全的。
使用互斥锁。
答案 3 :(得分:0)
总的来说,不,你无法逃避。在你琐碎的例子中,它可能会起作用,但它不可靠。
答案 4 :(得分:0)
只有在PC上有1个带有++和 - 原子操作的CPU时,它才是线程安全的。
如果你想让它的线程安全,这就是Windows的方式:
LONG volatile count = 0;
void Thread1()
{
::InterlockedIncrement( &count );
}
void Thread2()
{
if(::InterlockedDecrement( &count ) == 0 )
{
printf("Stuf");
}
}
答案 5 :(得分:0)
你需要两件事来安全地通过两个或更多线程安全地使用一个对象:操作的原子性和排序保证。
有些人会假装在某些平台上你在这里尝试的是安全的,例如任何类型int
的操作代表那些平台是原子的(甚至递增或其他)。这样做的问题是您不一定有订购保证。因此,当你希望并知道将同时访问此特定变量时,编译器不会。 (并且编译器正确地假设这个变量一次只能被一个线程使用:你不希望每个变量都被视为可能被共享。性能后果将是非常糟糕的。)
所以不要这样使用原始类型。您无法保证语言,即使某些平台有自己的保证(例如原子性),您也无法告诉编译器该变量是与C ++共享的。要么使用原子类型的编译器扩展,C ++ 0x原子类型,要么使用库解决方案(例如互斥锁)。并且不要让这个名称误导你:为了真正有用,原子类型必须提供排序保证以及名称附带的原子性。