c++ concurrency in action

使用多线程

good:分离功能,更容易理解和写;性能提高

bad:不一定提高性能;难以理解;占用系统资源;多线程的切换也要耗时

线程实际上也是有自己的一块内存的,join的时候也会清理这一块内存。

detach后主线程就无法再接触到线程了,但保证它在销毁的时候会清理资源。

线程函数的参数是直接拷贝的,而非像普通函数调用一样。因此引用的时候要用std::ref()。

当一个thread本身持有线程的时候,如果用移动拷贝把本身覆盖,那么原本的线程就会析构,也就调用了terminate。

多线程中应该避免指针和引用的传递使得保护数据不再被保护。

当需要对成员函数上锁的时候,应该注意他们是否会互相影响,如果会就需要用同一个锁。

thread_local的即便是在同一段程序被多次使用,但如果对于不同的线程是不一样的,每一个线程都会单独有一个。

避免持有锁的时候调用外部代码,避免循环lock,按顺序获取锁。

只有特意去调用shared的函数,才是共享锁,否则都是独占锁,比如lock_guard,因为它调用的是mutex.lock()而非mutex.lock_shared()。

嵌套锁一般是,比如每个成员函数都会进行上锁,但是某个成员函数可能调用另一个,这就导致会重复上锁。

由于实际上读的时候也需要上锁,因此,即便函数是const,mutex也需要lock,因此它必须是mutable。

shared_future本身只能调用一次get,但是它是可以拷贝的,也就可以在不同的对象上分别调用一次get()。

为了更方便的进行多线程,可以直接不共享数据,要有相同的数据的时候就对数据进行拷贝,比如进行消息传递。

对于relaxed,每一个原子变量对于每一个线程来说都是相同的顺序,但是快慢不与其他线程同步,其顺序也不与其他原子变量的顺序有任何关系。

对于acl_rel来说,当一个原子变量acquire到一个release的原子变量,那么就会立即产生一次定序,之后所读取都会读到release前的最后一个或者更后的操作。

总而言之,acl_rel只能让本线程的顺序让别的线程都知道一样,但不能让不同线程的写入顺序让别的线程知道都一样。而seq_cst就是不同线程的写入顺序也一样。而relaxed就是即便对于同一个线程,别的线程看到的不同原子变量的写入顺序都不一样,只是对于每一个原子操作来说是一样的。

或者说不是不同原子变量之间的,也可以是原子变量和非原子变量之间的。

另外,内存序解决的是不同原子变量操作之间的顺序问题,而不同线程之间对于相同原子操作的顺序本身就不是内存序要解决的事情,他们的任意排列本身就是多线程定义内会发生的事情,只要保证他们的原子性,那么他们就是合法的。

至于栅栏可以理解就是不让前后调整,或者只允许往前或者往后。

感觉吧多线程会比当线程更加注重异常的问题,因为因为异常导致条件变量无法通知,那我觉得在使用条件变量notify也应该变成RAII的。另外需要注意所有的中间过程,不能让任何中间过程被打断。

当改造成多线程的时候,有些接口就不适用于多线程,比如队列,pop就应该改为两个,一个try_pop,一个wait_pop等等。而对于迭代器,那在多线程中那更是烂完了,因为这样就能让外部自由访问需要上锁的数据了,因此一般提供for_each之类的迭代函数作为替代。

但除了上锁实际上还有两种方式实现多线程,一种是无锁结构(更高的并发度,更高的鲁棒性(锁很难保持),但很耗费cpu且原子变量的操作也很耗时),另一种是消息传递模型(不要通过共享内存来通信,而要通过通信来共享内存)。

写无锁的时候还是慢慢放宽内存序。内存方面无锁也需要注意。

多线程也可以使用c++的一些内置的,比如std::for_each。而为了避免无限线程的问题(async也会避免这个问题,会控制在最佳的情况),也可以使用线程池。确定当前可以去完成哪些任务分配给线程池,然后等完成后再分配下一波。也可以将完全不同的功能放在不同的线程中,或者直接每个线程是流水线中的某一步。

但无论如何都要减少多线程对于同一内存位置的竞争。多线程中对于处理数据的划分也很重要,因为缓存的存在。

jthread实际上还是不够完善,如果线程是在wait的状态,那么request_stop也就没有效果了。有两种方法解决,一种是wait不要永久wait,而是while(){wait(,1ms)}之类的,等一下,然后判断一下stop_token,另一种是让这个mutex是自己设计的,和stop_token进行联动,然后使用cv_any。

活锁:循环中持续检查(自旋锁)

关于调试,如果在使用线程池,可以强行让它上限为1,如果这样没有出错,但是不为1的时候出错了,那么就是多线程的问题。


c++ concurrency in action
https://lhish.github.io/project/c++ concurrency in action/
作者
lhy
发布于
2025年8月16日
许可协议