简体   繁体   English

使用 std::shared_ptr/weak_ptr 的简化观察者模式

[英]simplfied observer pattern with std::shared_ptr/weak_ptr

Here is a simplified observer pattern:这是一个简化的观察者模式:

  1. one creator creates a profile when it starts and "destroy" it when it is done.一位创建者在启动时创建配置文件,并在完成时“销毁”它。
  2. zero, one or more observers try to "look at" the profile at any time.零,一个或多个观察者随时尝试“查看”配置文件。

To implement it, the trick is that observers shall refcnt profile, so the last observer (or creator) can safely destroy it.要实现它,诀窍是观察者应该 refcnt 配置文件,因此最后一个观察者(或创建者)可以安全地销毁它。

I can do it without shared_ptr/weak_ptr, but I wonder if using them can avoid re-inventing wheels.我可以在没有 shared_ptr/weak_ptr 的情况下做到这一点,但我想知道使用它们是否可以避免重新发明轮子。

Here is my code:这是我的代码:

#include <iostream>
#include <memory>
#include <thread>
#include <cassert>

volatile bool playing = true;

class Profile {
public:
    int a_;
    Profile(int v) {a_ = v;}
};

std::shared_ptr<Profile> g_profile{ nullptr };

void observer() {
    do {
        // observe profile if I can
        std::weak_ptr<Profile> weak = g_profile;
        if (auto prof = weak.lock()) {
            auto a = prof->a_;
            // if prof is stable, I shall see the same a_
            assert(a == prof->a_);
        }
        else {
            std::cout << ".";
        }
    } while (playing);
}

void creator() {
    do {
        // create profile when I start
        g_profile.reset(new Profile(std::rand()));
        std::weak_ptr<Profile> weak = g_profile;
        assert(weak.lock() != nullptr);
        
        // doing some work ...

        // destroy profile when I am done
        g_profile.reset();
    } while (playing);
}

void timer() {
    std::this_thread::sleep_for(std::chrono::seconds(10));
    playing = false;
}

int main() {
    std::thread cr{ creator };
    std::thread ob{ observer };
    std::thread tm{ timer };
    cr.join();ob.join();tm.join();

    // no memory leak
}

But the program crashes either at std::weak_ptr<Profile> weak = g_profile or assert(a == prof->a_) .但是程序在std::weak_ptr<Profile> weak = g_profileassert(a == prof->a_)处崩溃。 So here are my questions:所以这是我的问题:

  1. do you have a pointer implementing observer pattern (or variant) with shared_ptr/weak_ptr?你有一个指针用shared_ptr/weak_ptr实现观察者模式(或变体)吗?
  2. what's wrong with the above code?上面的代码有什么问题? Can you make it right?你能做对吗?

You have undefined bahavior when one thread reads from the shared pointer g_profile (observer) while the other thread writes to it (when creator calls std::shared_ptr::reset )当一个线程从共享指针g_profile (观察者)读取而另一个线程写入它时(当创建者调用std::shared_ptr::reset时),您有未定义的行为

If you want to use the shared_ptr from two threads you'll have to use a lock or atomic_shared_ptr .如果要从两个线程中使用shared_ptr ,则必须使用 lock 或atomic_shared_ptr

Also volatile does not guarantee any synchronization as it does in java. volatile也不像在 java 中那样保证任何同步。 See this answer .看到这个答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM