【问题标题】:changing static variable in boost thread在 boost 线程中更改静态变量
【发布时间】:2013-06-24 16:41:08
【问题描述】:

我正在使用 boost 线程来运行 opengl 函数,而我的主线程旨在通过标准输入和输出与外部程序进行通信。原因是一旦 opengl 进入主循环,它就永远不会离开,但我需要一种在不阻塞渲染的同时读取输入的方法。一旦程序接收到输入,主程序通过静态成员与opengl线程通信(只需更改值)

class ARGraphicController
{
    public:
        ARGraphicController(int sw, int sh);
        ~ARGraphicController();
        //...
        void start(int argc, char *argv[]);
        static void changeGen();
        static bool genMove;
    private:
        //..
};


bool ARGraphicController::genMove;
void ARGraphicController::start(int argc, char *argv[])
{
    //opengl initialization
    //./
    glutMainLoop();
}

这是我的主线

void main()
{
    graphic_handler = new boost::thread(boost::bind(&ARGraphicController::start, &graphic_controller, argc, argv));

    string command_line;

    while(1)
    {
        getline(cin, command_line);
        //process input command
        //...
        //...

        if(command == "genmov"){
            //change static variable to true
            graphic_controller.changeGen();
            while(1)
            {
            //until the thread change the static variable back to false
                if(!graphic_controller.genMove)
                {
                    //...
                    break;
                }       
            }
        }

    }
    delete graphic_handler;
}

我不明白的是,如果我这样做,changeGen() 不会改变静态变量的值:

void ARGraphicController::changeGen()
{
    genMove = true;
}

但是当我添加一个 std::cout 时,值会改变..

void ARGraphicController::changeGen()
{
    genMove = true;
    std::cout<<"value is changed :)"<<std::endl;
}

我怀疑这与静态成员变量(本质上是全局变量)不是线程安全的事实有关吗?如果是这样,我该如何解决这个问题?还是有更好的方法来设计我的应用程序以在我的主线程和线程之间进行通信?

谢谢

【问题讨论】:

  • 您使用的是 C++11 编译器吗?
  • 我不认为我启用了 c++11。我正在使用 Visual Studio 2010
  • VS2010 没有针对 C++11 功能的开关,因此它提供的所有功能始终处于活动状态。不幸的是,大多数与线程相关的东西都是在 VS2011 中引入的。

标签: c++ thread-safety boost-thread static-members


【解决方案1】:

欢迎来到memory ordering的精彩世界。

这里的问题是,在您当前的设置中,您无法保证写入的值何时对其他线程可见。任何编译器、CPU、缓存或内存控制器(可能还有其他)都可以在此处插入优化,以防止更改在第二个线程中变得可见。除此之外,您还有一场数据竞赛。对 bool 的非同步访问适用于大多数现代架构,但可能会严重破坏其他架构。在 ISO-C++11 中,这样的数据竞争会立即导致未定义的行为。

解决方案是利用线程库。这里最简单的解决方法是简单地将atomic&lt;bool&gt; 用于静态变量。这将处理排序和访问问题。或者,考虑一个消息传递原语:

  • 使用boost::future 表示一次性事件。
  • 使用boost::condition_variable 表示线程可以等待的重复条件(这里的突出示例是生产者-消费者)
  • 在发送大量统一消息时,使用来自boost.lockfree 的无锁队列在线程之间建立数据流。

【讨论】:

  • 可能是因为它改变了调度或以一种微妙的方式阻止了优化。问题是允许编译器在循环之前将graphic_controller.genMove 加载到寄存器中,之后不需要再次查看内存。因此,您的更改要么阻止编译器执行此操作,要么更改了调度,因此现在更有可能在进入循环之前已经设置了变量。但是,很难说出这种行为的原因。
  • 另外,对于使用原子类(c++11 特征),我认为 volatile 变量可能足以达到同样的目的?
  • 没有。 volatile 不保证订购。 VS2010 为 volatile 提供了额外的保证,但在 ISO-C++ 中,volatile 对线程几乎没有用处。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 2018-06-22
  • 2016-03-27
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
相关资源
最近更新 更多