pthreads应用程序中的赋值 我在C++中有一个Linux多线程应用程序。 在此应用程序中,在类应用程序中提供变量状态: class App { ... typedef enum { asStop=0, asStart, asRestart, asWork, asClose } TAppStatus; TAppStatus Status; ... }

pthreads应用程序中的赋值 我在C++中有一个Linux多线程应用程序。 在此应用程序中,在类应用程序中提供变量状态: class App { ... typedef enum { asStop=0, asStart, asRestart, asWork, asClose } TAppStatus; TAppStatus Status; ... },c++,linux,pthreads,C++,Linux,Pthreads,所有线程通常通过调用GetStatus()函数来检查Status inline TAppStatus App::GetStatus(){ return Status }; 应用程序的其他函数可以通过调用SetStatus()函数为Status变量分配不同的值,并且不使用互斥锁 void App::SetStatus( TAppStatus aStatus ){ Status=aStatus }; 编辑:所有线程在开关中使用状态 switch ( App::GetStatus() ){ cas

所有线程通常通过调用
GetStatus()
函数来检查
Status

inline TAppStatus App::GetStatus(){ return Status };
应用程序的其他函数可以通过调用
SetStatus()
函数为
Status
变量分配不同的值,并且不使用互斥锁

void App::SetStatus( TAppStatus aStatus ){ Status=aStatus };
编辑:所有线程在
开关中使用
状态

switch ( App::GetStatus() ){ case asStop: ... case asStart: ... };
  • 在这种情况下,赋值是原子操作吗
  • 这是正确的代码吗

  • 谢谢。

    这完全取决于所选的枚举表示形式。我相信,对于x86,所有操作系统字大小的赋值操作(x86为32位,x64为64位)以及该大小的对齐都是原子的,因此简单的读写操作是原子的

    即使假设它的大小和对齐方式正确,这也并不意味着这些函数是线程安全的,这取决于状态的用途

    编辑:此外,如果不使用原子操作或其他易失性访问,编译器的优化器可能会造成严重破坏


    编辑到您的编辑:不,这根本不是线程安全的。如果您手动将其转换为跳转表,那么您可能是线程安全的,我需要考虑一下。

    在某些体系结构上,此分配可能是原子的(偶然),但即使是原子的,此代码也是错误的。编译器和硬件可能会执行各种优化,这可能会破坏这种“原子性”。看看:


    使用锁或原子变量来修复它

    在C99或C++03中没有可移植的方法来实现同步变量,pthread库也不提供这种方法。你可以:

    • 使用C++0x
    • 使用其他提供原子操作的库,如
    • 使用锁,但这比快速操作本身慢几个数量级

    注:正如Martinho所指出的,虽然它们被称为“原子”,但对于存储和加载,它不是原子属性(操作不能中断,加载总是看到或看不到整个存储,这通常适用于32位存储和加载),而是排序属性(如果存储a和b,没有人可以获得新的b值和旧的a值)这很难获得,但在这种情况下是必要的。

    我强烈怀疑枚举是线程安全的…我怀疑赋值是原子操作。如果没有
    volatile
    关键字,它就永远不是原子的。“对volatile变量的操作不是原子性的,它们也不能为线程建立适当的“先发生后发生”关系。“volatile”的唯一含义是“嘿,你在那里,编译器,不要优化对这个东西的访问,好吗?”@Martinho:在一些平台上,声明volatile就足以使存储和加载原子化,“不要优化访问”“意味着“不要跨序列点重新排序”,这在某些平台上足以定义顺序(指令顺序正确,但缓存可能会破坏顺序)。@Jan:好的,它有时会起作用。但“如果没有volatile关键字,它永远不会是原子的。”是错误的。原子只意味着它发生在一个步骤上。它当然可以是原子的,没有易失性。它们是相关的,但是是正交的。@DeadMG:除非您使操作使用适当的屏障指令或锁前缀(根据给定平台的情况),否则它永远不会是线程安全的你需要内联汇编。大多数CPU都不能保证多个CPU/核心的L1缓存之间的一致性。对不起,什么是“Linux特定的”?你没有忘记那里的一个词吗?@Martinho:Oops,对不起,忘记了引号,所以
    中的头名被删除了。