posix线程和O3优化

时间:2011-07-28 23:08:48

标签: c++ optimization pthreads

我正在开发一个使用mpi(openmpi 1.4.3)和pthreads的程序,在linux下用c ++工作。

一些mpi节点有一个用pthreads实现的排队系统。 想法很简单,一个线程将元素添加到队列中,很少有其他的"工作"线程拾取对象并对其进行工作(不是火箭科学)。

请考虑我的工作线程的两个例子,它们会拾取元素。 除非指定-O3优化,否则第一个示例正常工作。在那种情况下,它开始无休止地循环而不会拾取任何东西。

    while (true){
        if (t_exitSignal[tID]){
            dorun = false;
            break;
        }

        //cout<<"w8\n";

        //check if queue has some work for us
        if (!frame_queue->empty()){

            //try to get lock and recheck that queue no empty
            pthread_mutex_lock( &mutex_frame_queue );

            if (!frame_queue->empty()){
                cout<<"Pickup "<<tID<<endl;
                con = frame_queue->front();
                frame_queue->pop();
                t_idling[tID] = false;
                pthread_mutex_unlock( &mutex_frame_queue );
                break;
            }

            pthread_mutex_unlock( &mutex_frame_queue );
        }

    }

现在考虑这个,完全相同的代码,除了在检查queue-&gt; empthy之前锁定mutex gettimg。这项工作适用于所有级别的优化。

    while (true){
        if (t_exitSignal[tID]){
            dorun = false;
            break;
        }
        //cout<<"w8\n";

        //try to get lock and recheck that queue no empty
        pthread_mutex_lock( &mutex_frame_queue );

        //check if queue has some work for us
        if (!frame_queue->empty()){

                cout<<"Pickup "<<tID<<endl;
                con = frame_queue->front();
                frame_queue->pop();
                t_idling[tID] = false;
                pthread_mutex_unlock( &mutex_frame_queue );
                break;

        }
        pthread_mutex_unlock( &mutex_frame_queue );

    }

以防它有所不同,这就是我从其他线程填充队列的方式

                    pthread_mutex_lock( &mutex_frame_queue );
            //adding the same contianer into queue to make it available for threads
            frame_queue->push(*cursor);
            pthread_mutex_unlock( &mutex_frame_queue );

我的问题是:为什么第一个代码示例停止工作为什么我用-O3选项进行编译? 排队系统还有其他建议吗?

非常感谢!

解决方案:这是我最后提出的。似乎比上述任何一种方法都要好得多。 (以防有人感兴趣;)

    while (true){

        if (t_exitSignal[tID]){

            dorun = false;
            break;
        }
        //try to get lock and check that queue no empty
        pthread_mutex_lock( &mutex_frame_queue );

        if (!frame_queue->empty()){

            con = frame_queue->front();
            frame_queue->pop();
            t_idling[tID] = false;
            pthread_mutex_unlock( &mutex_frame_queue );
            break;
        }else{

            pthread_cond_wait(&conf_frame_queue, &mutex_frame_queue);
            pthread_mutex_unlock( &mutex_frame_queue );
        }




    }

添加

        pthread_mutex_lock( &mutex_frame_queue );

        //adding the same contianer into queue to make it available for threads
        frame_queue->push(*cursor);
        //wake up any waiting threads
        pthread_cond_signal(&conf_frame_queue);
        pthread_mutex_unlock( &mutex_frame_queue )

2 个答案:

答案 0 :(得分:2)

我很想在第一次空检查之前建议__sync_synchronize(),但这可能不安全 - 如果另一个线程在添加到容器的中间,那个容器在你调用时可能仍然处于不一致状态empty()。根据容器的不同,任何事情都可能发生,从错误的答案回到崩溃。

Josh也可能是对的。锁定互斥锁还会提供内存屏障,这意味着您的代码将重新读取它所使用的内存,以确定每次容器是否为空。如果没有某种内存障碍,那么实际上从未确保过这种情况,因此在更高的优化级别下,您的代码可能永远不会看到更改。

另外,你看过pthread的condition variables吗?它们允许您在循环中避免轮询,直到容器不再为空。

答案 1 :(得分:1)

当你检查队列是否为空时,我猜你会看到一个基于指令排序假设的错误 - 当你打开优化时,订单会发生变化而且它会因为你所拥有的互斥锁没有出现而中断记忆障碍,以防止这种情况发生。