C++ 数据竞赛?但是问题出在哪里呢?

C++ 数据竞赛?但是问题出在哪里呢?,c++,multithreading,crash,C++,Multithreading,Crash,下面的简单程序偶尔会崩溃,但我不明白它会有什么问题 它是用“-pthread-std=c++11-g-O2-pie-fpie-std=c++11”编译的 valgrind drd报告了一场数据竞赛,但我不明白为什么 #include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <iostream> bool running; pthread_rwlock_t _rwlo

下面的简单程序偶尔会崩溃,但我不明白它会有什么问题

它是用“-pthread-std=c++11-g-O2-pie-fpie-std=c++11”编译的 valgrind drd报告了一场数据竞赛,但我不明白为什么

#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>

bool running;
pthread_rwlock_t _rwlock;

class Dummy {
public:
    Dummy() : _refs(0) {
        Ref();
    }
    volatile int _refs;

    void Ref() {
        ++_refs;
    }
    void Unref() {
        --_refs;
        if (_refs <= 0) {
            delete this;
        }
    }
};

static Dummy* s_dummy;

Dummy* get_dummy() {
    pthread_rwlock_rdlock(&_rwlock);
    Dummy* ret = s_dummy;
    ret->Ref();
    pthread_rwlock_unlock(&_rwlock);
    return ret;
}

void *work1(void*) {
    while (running) {
        Dummy* new_dummy = new Dummy();
        pthread_rwlock_wrlock(&_rwlock);
        Dummy* to_del = s_dummy;
        s_dummy = new_dummy;
        pthread_rwlock_unlock(&_rwlock);
        to_del->Unref();
    }
}

void *work2(void*) {
    while (running) {
        Dummy* p = get_dummy();
        p->Unref();
    }
}

int main() {
    running = true;
    pthread_rwlock_init(&_rwlock, NULL);
    s_dummy = new Dummy();
    pthread_t threads[2];

    threads[0] = pthread_create(&threads[0], NULL, work1, NULL);
    threads[0] = pthread_create(&threads[1], NULL, work2, NULL);

    sleep(30);
    running = false;

    void* ret;
    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], &ret);
    }

    return 0;
}
#包括
#包括
#包括
#包括
布尔跑;
pthread_rwlock_t_rwlock;
类虚拟{
公众:
Dummy():\参考文献(0){
Ref();
}
挥发性内标;
void Ref(){
++_参考文献;
}
void Unref(){
--_参考文献;
如果(_refsref();
pthread_rwlock_unlock(&_rwlock);
返回ret;
}
无效*工作1(无效*){
(跑步时){
虚拟*新虚拟=新虚拟();
pthread_rwlock_rwlock(&_rwlock);
假人*至_del=s_假人;
s_假人=新的_假人;
pthread_rwlock_unlock(&_rwlock);
到_del->Unref();
}
}
无效*工作2(无效*){
(跑步时){
Dummy*p=get_Dummy();
p->Unref();
}
}
int main(){
运行=真;
pthread_rwlock_init(&_rwlock,NULL);
s_假人=新假人();
pthread_t线程[2];
线程[0]=pthread_create(&threads[0],NULL,work1,NULL);
线程[0]=pthread_create(&threads[1],NULL,work2,NULL);
睡眠(30);
运行=错误;
void*ret;
对于(int i=0;i<2;++i){
pthread_join(线程[i]、&ret);
}
返回0;
}

work1和work2中的两个UNREF可能会冲突。没有任何东西可以阻止删除同时发生在两个线程中

另外,您应该使
运行
易失性,或者更好的是原子性

最后,对于一些可以使用共享的ptr轻松解决的问题,似乎需要做大量的工作。下面的代码与您的代码相当:

#include <atomic>
#include <memory>
#include <thread>

class Dummy {
};

std::atomic<bool> running = true;
static std::shared_ptr<Dummy> s_dummy = std::make_shared<Dummy> ();

void work1 () {
    while (running)
        s_dummy = std::make_shared<Dummy> ();
}

void work2 () {
    while (running) 
        s_dummy = nullptr;
}

int main() {
    std::thread t1 (work1);
    std::thread t2 (work2);

    sleep (30);
    running = false;

    t1.join ();
    t2.join ();

    return 0;
}
#包括
#包括
#包括
类虚拟{
};
std::原子运行=真;
静态std::shared_ptr s_dummy=std::make_shared();
无效工作1(){
(跑步时)
s_dummy=std::使_共享();
}
无效工作2(){
(跑步时)
s_dummy=nullptr;
}
int main(){
标准:螺纹t1(工作1);
标准:螺纹t2(工作2);
睡眠(30);
运行=错误;
t1.join();
t2.join();
返回0;
}

由于您没有添加消息,因此我无法说明您收到的确切消息,但是您至少在
\u refs
上有一个数据竞争,这可能会导致双重
删除

例如,两个线程可以同时位于同一对象上的
Unref
,且_refsinitial==2

假设两个线程都运行
-\u refs
,那么
\u refs
的值将为0。然后两个线程都检查
refs
是否为零,并且由于
\u refs
是易失性的,因此它们都从内存中读取值0,并且都删除


您可能希望
\u refs
是一个原子变量,而不是一个易失性。

不应该
线程[0]=pthread\u create(&threads[1],NULL,work2,NULL);
be
threads[1]=pthread\u create(&threads[1],NULL,work2,NULL);
实际上是对
线程[0]的两个赋值
应该被删除,您只需调用
pthread\u create()
如果您不想检查错误,因为赋值将破坏该函数编写的线程标识符。我想可能是
\u refs
上的数据竞争?您可以添加给出的消息吗?您是否在x86以外的处理器上运行此操作?比如说,ARM?如果是这样,我怀疑不同内核上的缓存不正确rly已同步。我是说_refs导致了故障、数据竞争,但这怎么可能发生呢?