Denken und Selbstbeobachtung eines falschen Programms unter Rennbedingungen in der Multithread-Programmierung

Code direkt 

#include <memory>
#include <iostream>
#include <string.h>
#include <vector>
#include <pthread.h>
using namespace std;

class MutexLock
{
public:
    MutexLock()
    {
        pthread_mutex_init(&_mutex, NULL);
    }

    ~MutexLock()
    {
        pthread_mutex_destroy(&_mutex);
    }

    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    pthread_mutex_t * getMutexLockPtr()
    {
        return &_mutex;
    }
private:
    pthread_mutex_t _mutex;
};

//RAII
class MutexLockGuard
{
public:
    MutexLockGuard(MutexLock & mutex)
            : _mutex(mutex)
    {
        printf("lock\n");
        _mutex.lock();
    }

    ~MutexLockGuard()
    {
        printf("unlock\n");
        _mutex.unlock();
    }

private:
    MutexLock & _mutex;
};

//end of namespace wd

class Observable;

class Observer{
public:
    virtual void update() = 0;
};

class Foo : public Observer
{
public:
    virtual void update()
    {
        printf("%ld:Foo::update() %p\n",pthread_self(), this);
    }
};


class Observable{
public:
    void register_(weak_ptr<Observer> x)
    {
        observers.push_back(x);
    }

    void notifyObservers()
    {
        MutexLockGuard guard(mutex_);
        Iterator it = observers.begin();
        while(it != observers.end())
        {
            shared_ptr<Observer> obj(it->lock());

            if(obj)
            {
                obj->update();
            }else{
                it = observers.erase(it);
            }
            it++;
        }

    }

private:
    mutable MutexLock mutex_;
    vector<weak_ptr<Observer>> observers;
    typedef std::vector<weak_ptr<Observer>>::iterator Iterator;
};

Observable subject;
int sum = 10;

void* threadOne(void* arg)
{
        int count = 0;
        shared_ptr<Foo> foo = make_shared<Foo>();
        weak_ptr<Foo> w(foo);
        subject.register_(w);
        subject.notifyObservers();


}

void* threadTwo(void* arg)
{
    int count = 0;
    shared_ptr<Foo> foo = make_shared<Foo>();
    subject.register_(foo);
    subject.notifyObservers();


}

void* threadThree(void* arg)
{
    int count = 0;
    shared_ptr<Foo> foo = make_shared<Foo>();
//    subject.register_(foo);
//    subject.notifyObservers();
    count++;
}

int main()
{

    pthread_t thread1;
    pthread_t thread2;
    pthread_t thread3;
    pthread_create(&thread1, nullptr,threadOne,nullptr);
    pthread_create(&thread2,nullptr,threadTwo,nullptr);
    pthread_create(&thread3,nullptr,threadThree,nullptr);

    pthread_join(thread1,nullptr);
    pthread_join(thread2,nullptr);
    pthread_join(thread3,nullptr);

}

 

In der Tat können Sie über diesen Code nachdenken. Was ist daran falsch?

 

Die Hauptursache ist, dass mein Thread keine Zeitsteuerung durchgeführt hat  

threadOne

 

threadTwo

 

threadThree
 

Diese drei Funktionen können sich in einem anderen Thread befindensubject.notifyObservers运行完成之前就结束了,所以observers.erase(it)的时候这个对象已经被释放掉了,然后再次对他observers.erase可能core dump就是他最好的归宿了,所以在这种情况下即使加了锁也并不是安全的 

 

最后我们用一个例子来说明这个问题

 

Dies ist ein falsches Beispiel:

int main()
{


    vector<weak_ptr<Foo>> observers;
    ;
    {
        shared_ptr<Foo> p(new Foo);
        weak_ptr<Foo> f(p);
        observers.push_back(f);

    }

    std::vector<weak_ptr<Foo>>::iterator Iterator = observers.begin();
    while(Iterator != observers.end())
    {
        shared_ptr<Observer> obj(Iterator->lock());

        if(obj)
        {
            obj->update();
        }else{
            Iterator = observers.erase(Iterator);
        }
        Iterator++;
    }

}

 

Nach dem Verlassen des Gültigkeitsbereichs wurde schwach_ptr <Foo> f freigegeben und angezeigt

Prozess beendet mit Exit-Code 139 (unterbrochen durch Signal 11: SIGSEGV)

 

aber

int main()
{


    vector<weak_ptr<Foo>> observers;
    ;
    {
        shared_ptr<Foo> p(new Foo);
        weak_ptr<Foo> f(p);
        observers.push_back(f);
        std::vector<weak_ptr<Foo>>::iterator Iterator = observers.begin();
        while(Iterator != observers.end())
        {
            shared_ptr<Observer> obj(Iterator->lock());

            if(obj)
            {
                obj->update();
            }else{
                Iterator = observers.erase(Iterator);
            }
            Iterator++;
        }
    }



}

Wenn dies der Fall ist, gibt es kein Problem, alles ist in Ordnung, da der schwache_ptr nicht freigegeben wird, weil er nicht außerhalb des Gültigkeitsbereichs liegt

/home/zhanglei/ourc/test/cmake-build-debug/test-cpp
140718134794048:Foo::update() 0x55bee3748e70

Process finished with exit code 0

Der Grund für den Fehler ist, dass ich Iterator keinen Iterator ++ geben sollte, aber immer noch Coredump angezeigt wird. Ich bin wirklich verwirrt über den Grund.

 

Schließlich überprüfte ich den c ++ - Primer und sah die Einführung von Erase im Buch

 

Löschen löscht das angegebene Element im Iterator p und gibt einen Iterator zurück, der auf das gelöschte Element zeigt. Wenn es das Ende ist, zeigt es auf den Off-the-End-Iterator

 

Wenn wir also Löschen verwenden, geben Sie Iterator ++ nicht mehr an

 

Schließlich schreiben wir ein thread-sicheres Beobachtermuster

#include <memory>
#include <iostream>
#include <string.h>
#include <vector>
#include <pthread.h>
using namespace std;

class MutexLock
{
public:
    MutexLock()
    {
        pthread_mutex_init(&_mutex, NULL);
    }

    ~MutexLock()
    {
        pthread_mutex_destroy(&_mutex);
    }

    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    pthread_mutex_t * getMutexLockPtr()
    {
        return &_mutex;
    }
private:
    pthread_mutex_t _mutex;
};

//RAII
class MutexLockGuard
{
public:
    MutexLockGuard(MutexLock & mutex)
            : _mutex(mutex)
    {
        _mutex.lock();
    }

    ~MutexLockGuard()
    {
        _mutex.unlock();
    }

private:
    MutexLock & _mutex;
};

//end of namespace wd

class Observable;

class Observer{
public:
    virtual void update() = 0;
};

class Foo : public Observer
{
public:
    virtual void update()
    {
        printf("%ld:Foo::update() %p\n",pthread_self(), this);
    }
};


class Observable{
public:
    void register_(weak_ptr<Observer> x)
    {
        MutexLockGuard guard(mutex_);
        observers.push_back(x);
    }

    void notifyObservers()
    {
        MutexLockGuard guard(mutex_);
        Iterator it = observers.begin();
        while(it != observers.end())
        {
            shared_ptr<Observer> obj(it->lock());
            if(obj)
            {
                obj->update();
                it++;
            }else{
                it = observers.erase(it);
            }
        }

    }

private:
    mutable MutexLock mutex_;
    vector<weak_ptr<Observer>> observers;
    typedef std::vector<weak_ptr<Observer>>::iterator Iterator;
};

Observable subject;
int sum = 10;

void* threadOne(void* arg)
{
    shared_ptr<Foo> foo = make_shared<Foo>();
    weak_ptr<Foo> w(foo);
    subject.register_(w);
    subject.notifyObservers();


}

void* threadTwo(void* arg)
{
    shared_ptr<Foo> foo = make_shared<Foo>();
    subject.register_(foo);
    subject.notifyObservers();


}

void* threadThree(void* arg)
{
    shared_ptr<Foo> foo = make_shared<Foo>();
    subject.register_(foo);
    subject.notifyObservers();
}

int main()
{

    pthread_t thread1;
    pthread_t thread2;
    pthread_t thread3;
    pthread_create(&thread1, nullptr,threadOne,nullptr);
    pthread_create(&thread2,nullptr,threadTwo,nullptr);
    pthread_create(&thread3,nullptr,threadThree,nullptr);

    pthread_join(thread1,nullptr);
    pthread_join(thread2,nullptr);
    pthread_join(thread3,nullptr);
}

 

Beachten Sie, dass push_back nicht threadsicher ist. Es gibt keine Sperre. Es kann in einen anderen Thread aufgeteilt werden, wenn register_ auf halbem Weg ist und der Vektoriterator dann unvollständig ist, sodass er auch gesperrt werden muss.

Ich denke du magst

Origin blog.csdn.net/qq_32783703/article/details/105301601
Empfohlen
Rangfolge