线程同步
线程同步
同步: 在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。
竞态条件: 因为时序问题,而导致程序异常,我们称之为竞态条件。
没有同步导致的饥饿问题:
假如有一个线程,它非常强势,它一直都在申请锁,然后申请完了释放锁,释放完了又不给别的线程留机会,自己又去申请锁,那么此时如果有线程想要访问临界资源就必须等它彻底走了,那么有越来越多的线程想要访问临界资源,这个线程又一直不给让路,那么就会导致其他线程长时间得不到cpu资源从而导致其他线程的饥饿问题。所以这种情况就应该要加上同步机制,让这个线程申请一次释放之后就排在等待队列最后进行等待按顺序访问临界资源,让其他线程进行临界资源的访问。
没有同步导致的效率问题:
假如,有一个读线程,一个写线程,它们往管道里进行数据的读写,那么如果写线程写满了,该让读线程来读取数据了,但是此时读线程不知道已经写好了,一直不去读,写线程就会不断地去检测管道里是否有空间可以写数据,这样就会造成效率的低下,因此此时需要加上同步机制,当写线程写完的条件满足时,通知读线程来进行数据的读取,同样的,读线程读完的条件满足时,通知写线程来进行数据的写入,这样就达到了按照一定的顺序访问临界资源。
所以需要引入条件变量相关函数来解决线程的等待和通知问题:
- 条件不满足时,就挂起等待
- 条件满足时通过条件变量就会通知另外的进程来执行其他的操作
初始化:pthread_cond_init
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数:
cond: 要初始化的条件变量
attr: 属性,一般设置为NULL
销毁:pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *cond)
等待条件满足:pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
cond: 要在这个条件变量上等待(把当前线程挂起)
mutex: 互斥量(把当前线程拿到的锁释放)
为什么第二个参数要传互斥量?
因为等待条件满足是在临界区里等待的,如果某个线程直接进行等待,那么就会抱着锁去等待,此时,其他线程也无法进入临界资源。
- 条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程。
- 条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据。
唤醒等待:pthread_cond_signal/phread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_broadcast唤醒多个线程
pthread_cond_signal唤醒一个线程
条件变量使用规范
等待条件代码
pthread_mutex_lock(&lock); ------上锁
while(条件不成立)
{
pthread_cond_wait(&cond); ------条件不成立时挂起等待(注意是while)
}
进行操作...... ------修改、操作
pthread_mutex_unlock(&lock); ------解锁
给条件发信号代码
pthread_mutex_lock(&lock); ------上锁
设置条件为真... ------符合条件
pthread_cond_signal(&cond); ------唤醒
pthread_mutex_unlock(&lock); ------解锁
示例代码
相关阅读
一、临界区临界区又称关键代码段,指的是一小段代码在代码执行前,他需要独占一些资源。程序中通常将多线程同时访问的某个资源作为临