C++ 并发编程

您所在的位置:网站首页 linux多线程服务端编程会太老了吗 C++ 并发编程

C++ 并发编程

2024-07-15 05:57| 来源: 网络整理| 查看: 265

好长一段时间没有写文章了,这次总结一下陈硕大大写的《Linux多线程服务端编程》一书第二章的读书笔记。

1.互斥器(mutex)

使用互斥器的基本原则:

用RAII手法封装mutex的创建、销毁、加锁、解锁这四个操作。Java里面的synchronized语句和C#的using语句也有类似的效果,即保证所得生效期间等于一个作用于,不会因异常而忘记解锁。 只用非递归的mutex(即不可重入的mutext) 不手工调用lock()和unlock()函数,一切交给栈上的Guard对象的构造和析构函数负责。 在每次构造Guard对象的时候,思考一路上(调用栈上)已经持有的锁,防止因为锁顺序不同而导致死锁。 进程间通信使用socket,不要使用mutex。 加锁、解锁在同一个线程(RAII会保证)。 别忘记解锁(RAII会保证)。 不要重复解锁(RAII会保证)。 必要的时候可以考虑用PTHREAD_MUTEX_ERRORCHECK来排错。

基本的互斥器的代码如下:

class MutexLock { public: MutexLock() { pthread_mutex_init(&_mutex, NULL); } ~MutexLock() { pthread_mutex_destroy(&_mutex); } MutexLock& operator=(MutexLock& other) = delete; MutexLock(MutexLock& other) = delete; void lock() { pthread_mutex_lock(&_mutex); } void unlock() { pthread_mutex_unlock(&_mutex); } pthread_mutex_t* getRawMutex() { return &_mutex; } private: pthread_mutex_t _mutex; }; class MutexGuard { public: MutexGuard(MutexLock& mutex) :_lock(mutex) { _lock.lock(); } ~MutexGuard() { _lock.unlock(); } private: MutexLock& _lock; }; 2.条件变量(condition variable)

如果需要等待某个条件成立,我们应该使用条件变量。条件变量顾名思义是一个或多个线程等待某个布尔表达式为真,即等待别的线程“唤醒”它。条件变量的学名叫管程(monitor)。Java Object内置的wait()、notify()、notifyAll()是条件变量。对于wait端应该注意:

必须与mutex一起使用,该布尔表达式的读写接收此mutex的保护 在mutex已经上锁的时候才能调用wait() 把判断布尔条件和wait()放到while循环中

如下是一个简单的Condition实现

class Condition { public: Condition(MutexLock& mutex) :_mutex(mutex) { pthread_cond_init(&_cond, NULL); } ~Condition() { pthread_cond_destroy(&_cond); } void wait() { pthread_cond_wait(&_cond, _mutex.getRawMutex()); } void notify() { pthread_cond_signal(&_cond); } void notifyAll() { pthread_cond_broadcast(&_cond); } private: MutexLock& _mutex; pthread_cond_t _cond; }; 关于Spurious wakeup(虚假唤醒)

虚假唤醒在linux的多处理器系统中,在程序接收到信号前可能会发生。在Windows系统和JAVA虚拟机上也存在。在系统设计时应该可以避免虚假唤醒,但是这会影响条件变量的执行效率,而既然通过while循环就能避免虚假唤醒造成的错误,因此程序的逻辑就变成了while循环的情况。

3.copy-on-write

主要思想是这样的:让读的加锁粒度尽量的小,但当写数据的时候,新的读请求是阻塞的。

typedef std::shared_ptr MapPtr; MapPtr gData(new Map); // 有一个数据是需要共享的 MapPtr getData() { // 读数据只有这一段是加锁的 MutexGuard guard(mutex); return gData; } // read threads MapPtr _data = getData(); // process _data.... // write thread MutexGuard guard(mutex); // 写数据全场加锁 if(!gData.unique()) { MapPtr tmpData(new Map(gData.get())); gData.swap(tmpData); } // process _data ... 4.小结

记得两年前开始了解C++多线程编程的时候看了陈硕的这本书,工作两年,由于长时间使用Python,对C++已经有些陌生了,更别说C++多线程编程了,今天再次拾起这本书,重读前面两章就当复习了。接下来我会抽周末看一下《C++ Concurrency In Action》,也会陆续写一些相关的读书笔记。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3