unix高并发编程中遇到的问题和笔记

ps:本笔记不保证正确性,属个人总结

不定时更新

笔记:

乐观锁和悲观锁:在进行多线程操作的时候,刚刚会出现多个线程同时对一个数据进行读写,这时候为了保证数据一致性,需要对数据进行加锁。悲观锁指的是常见的锁,比如unix中的pthread_mutex_lock()。他的思想是,我不管你对数据做了什么操作,我都要锁起来,保证数据一致。乐观锁对数据不进行加锁,他只在数据进行写操作时进行判断,利用一条原子指令,c++中有一条CAS指令叫做__sync_bool_compare_and_swap(type * number, type oldNumber, type newNumber),number指针指向我们要保护的数据,他的操作是判断oldNumber和number指向数据进行比较,如果相同,那么number指向的数据变成newNumber的值。注意,这条指令是原子操作,由操作系统(或者是CPU指令)提供。对比下可以发现,悲观锁在阻塞等待占用的资源比较多,不适用读操作多的情况,乐观锁不加锁,所以适合读操作多的情况,但是缺陷是需要反复轮询。具体性能差异可以自行尝试。

(悲观)锁的种类:互斥量mutex,读写锁rwlock,条件变量cond,自旋锁spin,屏障。互斥量是最简单的锁,直接lock()锁上,或者阻塞等待unlock()。读写锁分为读锁和写锁,加了读锁后写操作会被阻塞,而加了写锁后读写操作都会被阻塞。条件变量是先在一个地方设置wait()阻塞住,然后在其他地方启动signal,发送信号给阻塞的线程。要与互斥量配合使用,原因是使用条件变量的时候,往往带一个判断条件,比如if (a == 0) wait();那么把a先锁起来。调用wait的时候,会传入一个锁作为参数,执行的时候会先解锁,再阻塞住,接受到信号再锁上,是一个原子操作。自旋锁是和互斥量相似,但是互斥量是利用休眠对线程进行阻塞,而自旋锁是利用忙等进行阻塞,类似于我们写的while(lock_num == 0);适用于锁占用时间不长的情况,和一些不能休眠的线程,比如中断处理程序,现在一些互斥量会采取自旋一段时间,然后再休眠的做法提高效率。屏障,顾名思义,可以在某个地方设置一个屏障,然后设置一个count,代表等到多少个线程到达这里后取消阻塞。如果没有到达指定线程数,其他先到达的线程都会被阻塞住。

(悲观)锁的属性:进程共享/私有,超时时间,递归/非递归(可重入/不可重入),阻塞/非阻塞(lock/trylock)。进程共享/私有:可以设置这个锁是不是进程共享,底层实现是将锁所在空间映射到自己进程的独立空间上。超时时间:可以设置阻塞多久,如果超过超时时间,取消阻塞,并返回一个错误码ETIMEDOUT。递归/非递归(可重入/不可重入):同一个线程对同一个锁可以同时加锁多次,但是同样需要记数。其他线程想要加锁必须等待拥有锁的线程释放完该锁。作用是一定程度上避免死锁。考虑一种情况,同一个线程连续进行两次lock,两次unlock。如果采用非递归锁,会导致死锁,如果采用非递归锁就不会。他的思想是,同一个线程可以同时拥有一个资源多次,并不会产生冲突,因为你是一个线程,不可能同时读写多次造成数据不一致。

原子性:

可重入:

死锁情况:

死锁避免:

网络字节序:

问题:

猜你喜欢

转载自www.cnblogs.com/scaugsh/p/9395585.html