1、线程同步的概念:这里说的同步并非时同时的概念,而是指协同、协助、互相配合,即按照一定的次序完成需要的动作,使程序正常运行。所谓的线程同步,指的是一个线程某个功能调用时,没有得到结果之前,该调用不返回,同时其他线程为保证数据一致性,不能调用该功能。
2、互斥量:两个线程访问同一块资源,如果不协调顺序,容易造成数据混乱,这时候,就需要加上一把锁。例如,只有一个厕所,a先进去,为了防止下一个人进来,他就先把厕所门给锁住,等自己拉完过后再将门打开,这时候即释放了锁,下一个人就可以进去,再上锁,以此重复。
mutex
锁的初始化:int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
其中 restrict 代表强制使用mutex这个结构进行初始化,初始化锁有两种方式,一种是定义一个pthread_mutex_t 变量,之后调用init函数进行初始化,属性一般传NULL; 另一种就是通过宏进行初始化,即通过pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER来初始化一个全局锁。
摧毁锁: int pthread_mutex_destroy(pthread_mutex_t *mutex);
加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
如果该锁已经被占用,此时,会陷入阻塞等待状态。
int pthread_mutex_trylock(pthread_mutex_t *mutex);
如果该锁被占用,则会返回一个errnum,可以通过调用strerror(errnum)来获取错误信息。
解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
3、死锁:死锁一般有两种情况。
第一种是已经给上了一把锁,这时候你忘记你已经上了一把锁,这时候你又上了一把锁,这时候就会陷入阻塞等待状态,或者是又上了另一把锁,这时候其他线程要加锁时,也会因为原来的锁没释放,陷入阻塞等待状态;
第二种是交叉锁,比如线程a和线程b同时拥有两把锁才能进行任务执行,这时候a拿到锁1,b拿到锁2,a需要继续拿到锁2才能只能,b需要拿到锁1才能执行,这时候,a和b就都会陷入阻塞等待状态,产生死锁。
解决的办法就是合理分配锁,避免死锁产生。
4、读写锁:假如有一块共享资源,多个线程同时进行读数据的操作,这时候如果加正常的锁,必然会大大地浪费时间,因为数据本身不会变化;而进行写操作的时候,就不能有其他操作同时访问或者修改该共享资源的数据,这时候,就诞生的一种读写锁来满足这种需求。
读写锁特点:读共享、写独占、写的优先级高;
读写锁初始化:int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
读写锁销毁:int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
读锁:int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);阻塞
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);非阻塞
写锁:int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);非阻塞
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);阻塞
释放锁:int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);