陈硕《Linux 多线程服务端编程:使用 muduo C++ 网络库》笔记摘要

陈硕《Linux 多线程服务端编程:使用 muduo C++ 网络库》笔记摘要

前言

尽可能用 message passing 模型,避免 shared memory 模型。因为前者保证程序正确性更容易,并且移植到分布式系统中更简单。

第二章 线程同步精要

四项原则:

  • 首要原则是尽量最低限度的共享对象;
  • 其次是使用高级的并发编程构件:如TaskQueue, Produce-Consumer Queue, CountDownLatch;
  • 底层同步原语只使用非递归的互斥器和条件变量,慎用读写锁,不要用信号量;
  • 除了使用atomic整数之外,不自觉编写lock-free代码;

作者的个人原则:

  • 用RAII手法封装mutex的创建,销毁,加锁,解锁这4个操作;
  • 只用非递归的mutex;
  • 不手工调用lock()和unlock()函数;
  • 不使用跨进程的mutex,进程间通信只用TCP sockets;
  • 函数拆分重构,如果一个函数既可能在已经加锁的情况下调用,又可能在未加锁的情况下调用,那么就拆分成两个函数。
  • 线程安全的Singleton实现,使用pthread_once。

线程的销毁有几种方式:

  • 自然死亡。这是线程正常退出的方式。
  • 非正常死亡。抛出异常,或者触发信号等非法操作;
  • 自杀。调用pthread_exit()来退出。
  • 他杀。调用pthread_candel()来强制终止某个线程。

只用非递归锁是因为滥用递归锁更容易发生死锁,且不容易发现;
读写锁的问题有:

  • 正确性:程序员容易不小心在read lock保护的函数中调用修改状态的函数
  • 性能:读写锁开销总是大于等于mutex
  • 读锁如果可以提升为写锁,那么可能会造成可重入锁一样的问题
    信号量的问题有:
  • semaphore has no notion of ownership
  • 时刻保持信号量与我们自己数据结构长度值的一致,增加了程序猿的负担和出错的可能

copy-on-write & read-and-update
写时,可以先加锁拷贝变量副本,然后修改变量副本。读时,可以先临界区拷贝变量到函数局部变量,再操作函数局部变量来避免死锁。前者帮助避免修改正在读的数据,后者帮助避免死锁或者读正在修改的数据。

参考

posted @ 2022-03-19 21:16  与MPI做斗争  阅读(435)  评论(0编辑  收藏  举报