mutex原则
1.使用RAII手法封装锁,即mutex的创建销毁是在RAII封装之后的类的构造函数与析构函数里的。
2.使用非递归也就是说不可重入锁。
3.使用scoped locking也就是不手工去调用加锁解锁函数,指利用RAII的构造与析构
4.在每次构建锁RAII时,注意思考一路上函数调用时栈上的锁,防止因为加锁顺序不同导致死锁。由于锁在栈上,看函数调用栈就能观察出锁的使用情况非常方便。
5.不使用跨进城锁,进程通信只使用TCP套接字。
只使用不可重入锁
使用可重入锁的好处是在一个线程中重复加锁不会造成死锁,但是在多次加锁后,想改变一个数据结构,但是在之前的加锁中也在遍历修改这个数据,那么就可能造成crash或者迭代器失效。并且使用不可重入锁,在调试的时候也是比较容易的。因为直接打印栈的内容就可以了。
如果一个函数会分别在有锁跟无锁两种情况下调用那就把他们分成两个函数。
Linux下的Pthread mutex在加锁的时候不会每次都陷入内核。
锁的调用顺序会造成死锁,A锁上以后,B也锁上,然后A请求B锁,B请求A锁。
通过使用shared_ptr来实现copy_on_write
##读写锁
不使用读写锁
第一,读写锁难以维护,是因为在最开始写代码的时候这个地方是读的,但是后面更迭代码或者调试程序的时候很可能会修改数据,但是自己又意识不到。
第二,读写锁并不比普通的锁性能要好,并且在临界区很小并且锁的竞争并不激烈的时候,普通的互斥量要比读写锁性能要高。
第三,读写锁为了防止写锁饥饿,在写锁排队时会阻塞读锁。
第四,如果读锁中嵌套写锁,如果允许提升读锁就有可能造成在写锁的时候修改了读锁的遍历的数据结构,如果不允许提升读锁那就直接造成了死锁。
不使用信号量
因为信号量自己维护一个计数值,同时在编程的时候我们也要把资源数组的大小与信号量时刻保持一致,增加了负担与出锁的可能性。使用条件变量可以完美的替代信号量。不过条件变量在使用之前需要加上锁,但是在signal和broadcast的时候不需要加锁。