std::thread I – 加载(launch)新线程

标准库使用std::thread()启动一个线程, 原型如下:

最直接的方式就是顶一个函数, 将函数及其实参一同传入构造的thread实例, 此外, 在实际编码中, 还有几种常见的编码形式来启动一个线程

使用类

可以借助C++的类的封装, 将一个线程的资源和运行上下文封装在一起:

使用std::thread构造线程对象时, 如果使用临时对象而不是有名对象来构造, 就要注意下面这种写法是错误的.

事实上, 在编译器眼中, std::thread t(BackGroundTask()); 并不是用构造一个临时的BackGroundTask对象并用它来构造一个 std::thread对象, 而是声明了一个 “以函数对象为参数, 返回值为std::thread的函数t, 它的入参函数的参数是空, 返回值为BackGroundTask类型”. 如果修改这句话使之能够按照我们期望的方向构造std::thread实例, 可以改成下面两种写法:

使用lambda

从C++ XI开始, 有了引入的lambda表达式, 我们也可以不用上述的封装方式, 使用lambda的capture list也可以方便的实现有参线程的启动, 重要的是不用单独定义线程执行函数, 特别适合线程函数只启动一次的场景

条件变量 II – std::condition_variable

条件变量是多线程同步的一种常用方法, 两个线程同步, 如果一个线程在到达同步点之前可能等待很久, 以至产生的额外开销超过了线程调度的开销, 这种情况就可以使用条件变量来同步, 反之, 如果等待的开销比较小, 就可以使用while(){sleep_1ms()}的方式来完成同步, 类似的思路和内核的spin_lock和mutex的区别一样.

C++ STL 提供了相对完善的并行编程接口, 当然少不了对于条件变量的实现. 和pthread实现相比, 除了接口更加面向对象, 并无明显不同, 毕竟, “条件变量的正确使用方式只有一种”. 使用条件变量, 需要准备三件材料: 1个条件 + 2个变量 + 多个线程.

  • 1个条件: 和所有的并行代码一样, 搞清楚执行流之间何时同步, 如何同步是整个程序的重中之重
  • 2个变量: 1个条件变量 + 1把mutex, 当然, 在不同的语言中这种mutex的实现可以不同, 但其本质并没有改变
  • 多个线程: 条件变量只能用于多线程同步, 不能用于多进程
Continue reading

条件变量 I – pthread

条件变量是线程同步的另一种方式,实际上,条件变量是信号量的底层实现,这也就意味着,使用条件变量可以拥有更大的自由度,同时也就需要更加小心的进行同步操作。条件变量使用的条件本身是需要使用互斥量进行保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为互斥量必须在锁定之后才能计算条件。

模型

pthread_cond_init()

Continue reading

C++ MiniTrick

时间戳打印

master-slave工作线程各自初始化

在master-worker模型中, 二者的初始化逻辑往往不同, 如果第一个执行的线程是master, 可以使用下面的代码来标识出:

Continue reading

每线程变量

每线程变量有多种实现方式,最原始的方式即是使用数组等数据结构建立线程ID和要访问变量之间的关系, 本文讨论如何借助其他工具来实现变量的每线程存储。

__thread

__thread是gcc扩展关键字,可以实现被声明变量的每线程存储。

输出的结果:

Continue reading