数据竞争? segfault,但问题出在哪里?

时间:2016-03-20 07:02:21

标签: 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 _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;
}

2 个答案:

答案 0 :(得分:1)

由于您没有添加,因此我无法说出您收到的确切消息,但是您至少在_refs上进行了数据竞争,并且可能会导致双delete

例如,两个线程可以同时位于同一个对象的Unref内,_refs最初== 2.

假设两个线程都运行--_refs_refs的值将为0.然后两个线程检查refs是否为零,并且_refs是不稳定的两者都从内存中读取值0并且都删除。

_refs你可能想要的是 atomic 变量,而不是volatile。

答案 1 :(得分:0)

work1和work2中的两个unrefs可能会发生冲突。没有什么能阻止同时在两个线程中发生删除。

此外,你应该使running变得不稳定,或者更好。

最后,对于可以使用shared_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;
}