Linux多线程编程C++
文章平均质量分 71
linux下C++多线程编程实战
liuxuejiang158
做点笔记,省的百度不到。。。
展开
-
muduo简化(1):Reactor的关键结构
说明:本文参照muduo代码,主要用意是简化muduo代码呈现其主要结构,并脱离muduo的文件依赖。 本节简化的是Reactor的关键结构部分:EventLoop、Poller、Channel。遵照one loop per thread原则,一个事件循环对应一个IO线程,IO线程运行EventLoop事件主循环,该主循环loop调用IO复用器Poller监听事件集合,并将就原创 2013-11-17 21:17:24 · 2299 阅读 · 0 评论 -
Thread系列的RAII封装
#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include"Mutex.hpp"using namespace std;using namespace boost;/原创 2013-11-15 00:16:26 · 3098 阅读 · 0 评论 -
fork与多线程
如果一个多线程程序调用了fork,那么新创建的子进程只拥有一个执行线程(调用fork的那个线程的完整复制),并且子进程自动继承父进程的互斥锁(条件变量)的状态,即父进程中被加锁的互斥量在子进程中也是被锁住的。于是子进程不知道继承而来的互斥量的具体状态,若互斥量在fork前已经被加锁,子进程若再对互斥量加锁则一定死锁。当然若fork后的子进程立即调用exec()执行其它程序隔断了父子关系则不会出现上原创 2013-11-03 21:10:54 · 2510 阅读 · 0 评论 -
RAII封装TCP连接
文件描述符的分配方式:使用当前最小可用的文件描述符。在多线程环境中文件描述符容易出错:若一个线程A持有一个描述符fd,另一个线程B在close(fd)后立即open一个描述符刚好值等于前面的fd,那么线程A拿着fd读写是要出错的,线程不能感知描述符的死活。采用RAII手法封装描述符,对象析构时关闭描述符,只要对象还活着就不会有其它对象和它有一样的描述符。 给出一个简单粗糙的例子:服务端主原创 2013-11-03 17:07:26 · 2042 阅读 · 0 评论 -
线程私有数据TSD
在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据。在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效,但却可以跨多个函数访问,比如程序可能需要每个线程维护一个链表,而使用相同的函数操作,最简单的办法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由Posix线程库维护,称为线程原创 2013-11-03 10:50:21 · 2156 阅读 · 0 评论 -
__thread关键字
__thread是GCC内置的线程局部存储设施,存取效率可以和全局变量相比。__thread变量每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。 __thread使用规则:只能修饰POD类型(类似整型指针的标量,不带自定义的构造、拷贝、赋值、析构的类型,二进制内容可以任意复制memset,memcpy,且内容可原创 2013-11-03 09:04:29 · 27053 阅读 · 1 评论 -
exit:c++非线程安全
exit调用会终止整个进程,在_exit的基础上执行一系列用户空间操作比如刷新缓冲区。_exit是直接交给内核,exit先执行清除操作再交给内核。exit或_exit时,系统无条件的停止剩下所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。 因此exit在C++中非线程安全,看下面这个例子:#include#include#include#includeu原创 2013-11-02 21:48:58 · 2559 阅读 · 0 评论 -
有限容量BlockingQueue:消费者生产者
有限容量的BlockingQueue实现工作队列,用于生产者消费者问题。#include#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;using namespace boost;原创 2013-11-02 12:54:41 · 2179 阅读 · 0 评论 -
再看copy_on_write缩小临界区的例子
本例子是模拟的读者写者问题,采用shared_ptr+写时拷贝实现,其中我觉得一个比较值得注意的地方是考虑到对象可能在临界区析构而将析构移除临界区,这对于多线程来说要多看多思。#include#include#include#include#include#include#include#includeusing namespace std;using namespace原创 2013-10-31 21:53:24 · 1564 阅读 · 0 评论 -
pthread_once重塑singleton模式
单件模式是非线程安全的:// Single threaded versionclass Foo { private Helper helper = null; public Helper getHelper() { if (helper == null) { helper = new Helper(); }原创 2013-10-31 21:49:03 · 2517 阅读 · 0 评论 -
条件变量:BlockingQueue+CountDownLatch
条件变量pthread_cond_t又名管程,条件变量的正确使用方式:1 必须与pthread_mutex_t一起使用,条件的读写受互斥量保护2 必须在pthread_mutex_lock后才能调用pthread_cond_wait3 采用while抱住pthread_cond_wait,这样防止虚假唤醒(线程甚至在没有其它向条件变量发送信号的情况下就有可能会被唤醒) 阻塞队原创 2013-10-29 23:14:33 · 2056 阅读 · 0 评论 -
多个非同源的shared_ptr管理对象引起double free
有多个不同源的shared_ptr管理对象时会出现多次释放对象,这里不同源是指多组间不是通过拷贝构造、复制等手段而来的,即几组shared_ptr是独立声明的。#include#include#include#include#includeusing namespace std;using namespace boost;class test{ public:原创 2013-10-29 09:09:54 · 4263 阅读 · 0 评论 -
临界区重叠:移出临界区+shared_ptr写时拷贝
死锁例子: 一些函数看似其本身是线程安全的,但是当多个函数同时执行时出现了非线程安全。一个例子是多个函数在多线程下同时执行时临界区相互重叠#include#include#include#include#includeusing namespace std;class Request;class Inventory{ public:原创 2013-10-28 23:36:15 · 1748 阅读 · 0 评论 -
同一函数可能加锁可能不加锁使用
当一个函数可能在加锁状态下使用,也可能在不加锁状态下使用时,将函数分割为两个版本:加锁版本,不加锁版本如下例子:#include#include//#include#includeusing namespace std;class test{ public: void process(){ pthread_mutex_lock(原创 2013-10-28 20:25:24 · 2001 阅读 · 0 评论 -
STL与多线程+写时拷贝
STL并不是线程安全的,当多个线程同时读取STL时没什么问题。当多个线程中有写STL时则非线程安全,导致其它线程的end()检测或迭代器算术操作无意义,修改操作可能导致STL重新分配内存,原来的迭代器可能失效。要实现多线程安全:可以用锁机制,也可以将写操作推后。 例子:一个线程输出vector元素,另一个容器不断往vector添加元素。最后出现的结果可能时段错误,也可能运行正常。原创 2013-10-27 20:40:04 · 2827 阅读 · 0 评论 -
RAII:互斥量
RAII(资源获取即初始化)基本技术原理很简单,如果希望保持对某个重要资源的跟踪,那么创建一个对象,并将资源的生命期和对象的生命期相关联。这样的话,就可以利用c++复杂老练的对象管理机制来管理资源。最简单的形式是,当你构造一个对象的时候,其构造对象会获得一份资源,而析构函数则释放这份资源。采用对象管理资源,即使碰到意外的return、异常(C++保证如果抛出了异常,局部对象就会被销毁)甚至是邪恶的原创 2013-10-27 13:58:13 · 1791 阅读 · 0 评论 -
boost::bind
Bind 创建函数对象来绑定到一个函数(普通函数或成员函数)。不需要直接给出函数的所有参数,参数可以稍后给,这意味着绑定器可以用于创建一个改变了它所绑定到的函数的 arity (参数数量) 的函数对象,或者按照你喜欢的顺序重排参数。通常与boost::function一起使用#include#include#include#includeusing namespace std;u原创 2013-10-25 22:31:46 · 1511 阅读 · 0 评论 -
shared_ptr:弱回调技术
场景:公司company存有公司员工的信息,现在给定一个查询接口,给定员工姓名在公司中查找若找到返回员工信息,若没有找到在公司录入这个员工信息。 1 若简单在公司company中用一个容器保存staff信息,那么staff离职了需要清理容器否则staff信息一直存在。 2 又涉及了对象生命周期的管理,想到shared_ptr/weak_ptr,那么company用weak_原创 2013-10-24 23:34:35 · 4106 阅读 · 0 评论 -
shared_ptr:线程安全、循环引用
shared_ptr用来管理堆对象可以避免delete,但是注意shared_ptr本身是个对象因此其的声明周期、shared_ptr对象的读写操作非原子化那么在多线程环境下仍然存在很多问题,即shared_ptr对象本身的线程安全级别非100%。在多线程中访问同一个shared_ptr对象应该用mutex保护。 shared_ptr使用不当会延长锁管理的对象(假设为A)的生命周期,即有什原创 2013-10-23 23:33:09 · 3134 阅读 · 0 评论 -
boost智能指针重塑订阅者模式
boost智能指针: scoped_ptr 简单的单一对象的唯一所有权。不可拷贝。//一旦离开作用域所指对象立即释放 scoped_array 简单的数组的唯一所有权。不可拷贝。//管理数组 shared_ptr 在多个指针间共享的对象所有权。//指向一个对象该对象的引用计数加1,当引用计数将原创 2013-10-22 23:43:57 · 2101 阅读 · 0 评论 -
对象耦合的非线程安全
对象的关系: 组合:一个对象B是对象A的成员,这种关系A对B有生杀大权 关联:对象A知道对象B的属性和方法,A将对B操作,这种情形下A怎么知道B还活着?若A操作了不存在的B?还线程安全吗? 聚合:和关联类似,不过是强关联关系,即多了整体和局部的关系,比如:大象A拥有大象牙B...但是A怎么知道自己睡觉的时候B已经被原创 2013-10-21 23:11:18 · 1425 阅读 · 0 评论 -
一个函数锁住相同类型的多个对象造成的死锁
一个类型中有个互斥量变量,一个函数锁住这个类型的多个对象,由于编码不注意加锁顺序在多线程环境下造成了死锁。#include#include#include#includeusing namespace std;class test{//持有一个互斥锁 public: test(){ pthread_mutex_init(&mutex原创 2013-10-21 20:32:10 · 1977 阅读 · 0 评论 -
当构造函数泄露this指针时
当一个类正在构造时在构造函数中将this泄露给了其它对象,这在单线程串行执行情况下可能没有什么问题,但是在多线程下那么问题就比较大了。比如线程1负责构造这个对象A但是在构造函数中将this指针泄露给了其它线程所调用的对象B,不巧的是其它线程所调用的对象B看见A有些不爽将其析构了。那么最后A自以为一切构造好了返回,线程1然后对这个A操作,最后可怕的错误(比如段错误)无穷无尽的折磨线程1......原创 2013-10-20 22:23:33 · 3440 阅读 · 0 评论 -
C++自增操作与原子性
int自增操作到底是不是原子性?验证了下答案是否定的,当多线程遇到简单的自增操作时会出现问题,比如开启很多个线程同时对一个int自增后结果会随着系统负载出现不同的结果。代码验证:#include#include#includeusing namespace std;static int i=0;class test{ public: test():a(原创 2013-10-20 20:50:19 · 8282 阅读 · 0 评论 -
C++析构竞态
由于C++对象的生命周期需要程序员自己管理,因此析构可能出现竞态尤其是在多线程下,一个对象可以被多个线程访问时,下列情形:1 即将析构一个对象时从何得知其它线程是否在操作该对象2 若某个线程正欲操作对象时,如何得知其它线程是否在析构该对象,且正析构一半....程序模拟:#include#include#include#includeusing namespace std原创 2013-10-20 10:49:46 · 2196 阅读 · 0 评论