首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有多个线程的C++无锁队列崩溃

带有多个线程的C++无锁队列崩溃
EN

Stack Overflow用户
提问于 2017-10-27 13:10:43
回答 1查看 109关注 0票数 0

在为多线程编写代码时,我试图更好地理解控制内存顺序。我过去经常使用互斥变量来序列化变量访问,但我尽量避免使用互斥对象来提高性能。

我有一个指针队列,可以由多个线程填充,也可以被多个线程使用。它适用于单个线程,但当我使用多个线程运行时,它会崩溃。看起来,使用者可能会得到指针的副本,从而导致它们被释放两次。这有点难说,因为当我输入任何打印语句,它运行良好,不会崩溃。

首先,我使用预先分配的向量来保存指针。我保留3个原子索引变量来跟踪向量中哪些元素需要处理。值得注意的是,我尝试使用_queue类型,其中元素本身是原子的,这似乎没有帮助。以下是更简单的版本:

代码语言:javascript
复制
std::atomic<uint32_t> iread;
std::atomic<uint32_t> iwrite;
std::atomic<uint32_t> iend;
std::vector<JEvent*> _queue;

// Write to _queue (may be thread 1,2,3,...)
while(!_done){
    uint32_t idx = iwrite.load();
    uint32_t inext = (idx+1)%_queue.size();
    if( inext == iread.load() ) return kQUEUE_FULL;
    if( iwrite.compare_exchange_weak(idx, inext) ){
        _queue[idx] = jevent; // jevent is JEvent* passed into this method
        while( !_done ){
            if( iend.compare_exchange_weak(idx, inext) ) break;
        }
        break;
    }
}

来自同一班

代码语言:javascript
复制
// Read from _queue (may be thread 1,2,3,...)
while(!_done){
    uint32_t idx = iread.load();
    if(idx == iend.load()) return NULL;
    JEvent *Event = _queue[idx];
    uint32_t inext = (idx+1)%_queue.size();
    if( iread.compare_exchange_weak(idx, inext) ){
        _nevents_processed++;
        return Event;
    }
}

我要强调的是,我真的很有兴趣了解为什么这不起作用。实现其他一些预先制作的包将帮助我克服这个问题,但不会帮助我避免再次犯同样类型的错误。

UPDATE我正在标记亚历山大·科诺瓦洛夫的答案是正确的(见我在下面的答复中的评论)。如果有人看到此页面,“写”部分的更正代码是:

代码语言:javascript
复制
std::atomic<uint32_t> iread;
std::atomic<uint32_t> iwrite;
std::atomic<uint32_t> iend;
std::vector<JEvent*> _queue;

// Write to _queue (may be thread 1,2,3,...)
while(!_done){
    uint32_t idx = iwrite.load();
    uint32_t inext = (idx+1)%_queue.size();
    if( inext == iread.load() ) return kQUEUE_FULL;
    if( iwrite.compare_exchange_weak(idx, inext) ){
        _queue[idx] = jevent; // jevent is JEvent* passed into this method
        uint32_t save_idx = idx;
        while( !_done ){
            if( iend.compare_exchange_weak(idx, inext) ) break;
            idx = save_idx;
        }
        break;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-04 15:40:50

对我来说,当有两个作家和一个读者时,一个可能的问题就会发生。假设第一作者就在前面停了下来

代码语言:javascript
复制
 _queue[0] = jevent;

第二位作者通过iend发出信号,表示它的_queue1已准备好可读。然后,读取器通过iend看到_queue已经准备好被读取,所以我们有数据竞争。

我建议您尝试Relacy Race检测器,这在理想情况下适用于此类分析。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46975857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档