Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当另一个线程可以设置共享布尔标志(最多一次)时,读取共享布尔标志而不锁定它是否可以?_C++_Multithreading_Locking_Boolean_Monitor - Fatal编程技术网

C++ 当另一个线程可以设置共享布尔标志(最多一次)时,读取共享布尔标志而不锁定它是否可以?

C++ 当另一个线程可以设置共享布尔标志(最多一次)时,读取共享布尔标志而不锁定它是否可以?,c++,multithreading,locking,boolean,monitor,C++,Multithreading,Locking,Boolean,Monitor,我希望我的线程能够更优雅地关闭,所以我正在尝试实现一个简单的信号机制。我认为我不想要一个完全事件驱动的线程,所以我有一个工作线程,它有一种方法,可以使用一个关键部分监视器(我相信相当于一个C#锁): DrawingThread.h class DrawingThread { bool stopRequested; Runtime::Monitor CSMonitor; CPInfo *pPInfo; //More.. } DrawingThread.cpp vo

我希望我的线程能够更优雅地关闭,所以我正在尝试实现一个简单的信号机制。我认为我不想要一个完全事件驱动的线程,所以我有一个工作线程,它有一种方法,可以使用一个关键部分
监视器
(我相信相当于一个C#
):

DrawingThread.h

class DrawingThread {
    bool stopRequested;
    Runtime::Monitor CSMonitor;
    CPInfo *pPInfo;
    //More..
}
DrawingThread.cpp

void DrawingThread::Run() {
    if (!stopRequested)
        //Time consuming call#1
    if (!stopRequested) {
        CSMonitor.Enter();
        pPInfo = new CPInfo(/**/);
        //Not time consuming but pPInfo must either be null or constructed. 
        CSMonitor.Exit();
    }
    if (!stopRequested) {
        pPInfo->foobar(/**/);//Time consuming and can be signalled
    }
    if (!stopRequested) {
        //One more optional but time consuming call.
    }
}


void DrawingThread::RequestStop() {
    CSMonitor.Enter();
    stopRequested = true;
    if (pPInfo) pPInfo->RequestStop();
    CSMonitor.Exit();
}
我知道(至少在Windows中)
Monitor
/
lock
s是最便宜的线程同步原语,但我希望避免过度使用。我是否应该包装此布尔标志的每次读取?当请求停止时(如果在任务完成之前请求停止),它被初始化为false,并且仅设置一次为true


我的导师建议保护甚至是
bool
,因为读/写可能不是原子的。我认为这个一次性标志是证明规则的例外?

布尔赋值是原子的。这不是问题所在

问题是,由于编译器或CPU指令重新排序或数据缓存(即读取布尔标志的线程可能读取缓存的值,而不是实际更新的值),线程可能看不到其他线程对变量所做的更改


解决方案是内存隔离,它确实是由lock语句隐式添加的,但对于单个变量来说,它是一种过度杀伤力。只需将其声明为
std::atomic

不,您必须保护每一次访问,因为现代编译器和CPU在不考虑多线程任务的情况下对代码重新排序。来自不同线程的读取访问可能会起作用,但不一定要起作用。

如果不进行同步,在不同线程中读取可能修改的内容是绝对不可能的。需要什么级别的同步取决于您实际阅读的内容。对于基本类型,您应该了解原子读取,例如以
std::atomic
的形式

始终需要同步的原因是处理器将在缓存线中共享数据。如果没有同步,它没有理由将此值更新为在不同线程中可能更改的值。更糟糕的是,如果没有同步,如果存储在值附近的内容被更改和同步,它可能会写入错误的值。

我认为答案是“这取决于”。如果您使用的是C++03,标准中没有定义线程,您必须阅读编译器和线程库中的说明,虽然这种事情通常被称为“良性种族”

如果您使用的是C++11,良性竞争是未定义的行为。即使未定义的行为对基础数据类型没有意义。问题是编译器可以假设程序没有未定义的行为(另请参见第1部分和第2部分)。例如,编译器可能决定读取一次标志并缓存该值,因为在没有某种互斥或内存障碍的情况下在另一个线程中写入变量是未定义的行为

当然,您的编译器很可能承诺不会进行这种优化。你需要看看


最简单的解决方法是在C++11中使用
std::atomic
,或者其他类似的东西。

接受导师的建议(他们可能是对的)-即使他们不是你的工作的标记者,所以如果他们说需要,那么就需要。@John3136我导师的建议已经有10年了,这是我现在的工作。“布尔赋值是原子的”:仅仅出于兴趣,这是C++或C++标准所要求的吗?注意C++中声明的东西<代码>易失性<代码>对同步没有任何影响!编译器使用“<代码>易失性> /代码>以防止它省略和/或重新排序指令。(这与Java中的
volatile
的语义不同)。您还需要告诉CPU需要同步。您需要使用相应的指令,例如
std::atomic
@NiklasB。我认为这意味着:线程不能看到
bool
的不一致状态。从这个意义上讲,它确实是原子的。但是,这并不意味着该值是同步的以任何方式与不同的内核进行同步。要使这些内核成为原子的,您需要同步,例如使用
std::atomic
。在这里,原子性对我来说并不重要。变量要么处于原始状态,要么在更新启动后检测到不处于原始状态。此延迟的后果可能会有所缓解线程响应的目的。正如都铎指出的,我需要确保两个线程都从同一个位置读取。@Niklas B:原子的意思是,值不能“撕裂”"例如,一个32位机器上的长的可能会被分割成一半,因为它需要两个登记副本。当然,这并不意味着可见性。<代码> STD::原子< /代码>是C++ 2011的一部分。它通常是在平台提供的设施的顶部实现的。使用适当的处理器操作是非常重要的。如何调用和使用这些操作取决于平台。
std::atomic
为它们提供了一个很好的可移植接口。这基本上是正确的。您需要某种同步。您不需要像“关键部分”(请注意,部分“实际上不是一个编程构造,而是描述一段代码的属性;我意识到Windows不一致地将其用于另一种称为“互斥体”的东西。如果您说明了平台,我可能会知道您想要使用什么(现在坐在C++委员会会议讨论并发扩展中,应该有一些专家…)平台是三星的BADA。主张用代码< OSP::