《Linux多线程服务端编程-使用muduo C++网络库》学习笔记——第一章

本文是《Linux多线程服务端编程-使用muduo C++网络库》的学习笔记,主要探讨线程安全的对象生命期管理,包括构造与销毁的挑战、智能指针shared_ptr和weak_ptr的应用,以及对象池和弱回调的实现。强调了在多线程环境下,避免空悬指针、线程安全的Observer模式和正确使用智能指针的重要性。
摘要由CSDN通过智能技术生成

第1章 线程安全的对象生命期管理

对象在销毁时,出现的竞态条件:

  1. 析构时,对象的函数被其他线程执行;
  2. 正在执行对象的函数,如何保证不被其他线程析构;
  3. 执行对象的函数之前,这个对象是否还活着。

C++标准库的多数类不符合线程安全,比如vector、string等等。

构造不难

对象构造时从以下2点考虑到线程安全:

  1. 不可以在构造函数中注册回调函数,比如加入观察者。。。。
  2. 不可以在构造中,把this传给其他线程。

注册回调的方式应该是二段式构造:构造函数+initalize(),如下:

class Foo : public Observer
{
public:
    Foo();
    void observe(Observer* s)
    {
        s->register_(this);
    }
};

Foo* pFoo = new Foo;
Obervable* s = getSubject();
pFoo->observe(s);//二段式构造

销毁太难

空悬指针(dangling pointer):指向已经销毁的对象。
野指针(wild pointer):未经初始化的指针。

对于普通的成员函数,只需要使用mutex保证临界区不会重叠,就是线程安全的。但是mutex本身不是一直有效,析构会把mutex销毁!对于以下两个函数,使用mutex保护析构:

Foo::~Foo()
{
    Lockguard m(mutex_);
    //...
}
Foo::update()
{
    Lockguard m(mutex_);
    //...
}

//thread A
delete x;
x = nullptr;
//thread B
if (x)
{
    x->update();
}

以上代码,如果线程A首先执行,线程B阻塞在update调用之前,那么将x赋值为空指针的做法,完全无法避免竞争,线程B触发core dump。以上例子,说明对象销毁之后,把指针置为nullptr完全没用。作为数据成员的mutex不能保护析构。对于基类来说,在进入基类的析构函数之前,派生类的析构已经调用了,说明mutex也无法保护整个析构过程。

此外,mutex可能导致死锁,参考以下代码:

void swap(Foo& a, Foo& b)
{
    Lockguard m1(a.mutex_);
    Lockguard m2(b.mutex_);
    //...
}
//thread A
swap(a, b);

//thread B
swap(b, a);

总结:一个函数要锁住多个相同类型的对象,必须始终按照相同的顺序加锁,实际做法可以按照地址大小顺序加锁。

线程安全的Observer的难点

动态创建的对象是否还活着,看指针和引用是看不出来的。面向对象的程序中,对象之间的关系有3种:

  • composition(组合):b是a的成员,不存在竞争关系,是线程安全的;
  • aggregation(关联):a用到了b,a持有b的指针或者引用,但是a不能单独控制b的生命期;
  • association(聚合):不同于关联的“整体-部分”,聚合更加泛化,可以是一对多、多对一。。。

以观察者模式举例

//观察者
class Observer
{
public:
    void update();
    void ob(Observable* s)
    {
        s->register_(this);
        subject_ = s;
    }
    ~Oberver()
    {
        subject_->unregister(this);
    }
    Observable* subject_;
}

//被观察的
class Observable
{
public:
    void register(Observer* s);
    void unregister(Observer* s);
    
    void notify()
    {
        for (Observer* x : observers_)
        {
            x->update();
        }
    }
    
    vector<Observer*>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值