Linux操作系统--多线程(锁、线程同步)
目录
1.常见锁概念:
1.1死锁
1.2死锁的四个必要条件
1.3避免死锁
2.Linux线程同步
2.1条件变量
2.2同步概念与竟态条件
2.3条件变量函数
2.4条件变量使用规范
1.常见锁概念:
1.1死锁
- 死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占,永不会释放的资源而处于的一种永久等待状态
1.2死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个执行流使用(前提)
- 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放(原则)
- 不剥夺条件:一个执行流已获得的资源,在未使用完之前,不能强行剥夺(原则)
- 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系(重要条件)
1.3避免死锁
- 破坏死锁的四个必要条件
- 加锁顺序一致
- 避免锁未释放的场景
- 资源一次性分配
2.Linux线程同步
2.1条件变量
- 当一个线程互斥地访问某个变量时,它可能发现在其他线程改变状态之间,它什么也做不了
- 例如一个线程访问队列时,发现队列为空,它只能等待,只到其他线程将一个节点添加到队列中。这种情况就需要用到条件变量
2.2同步概念与竟态条件
- 同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步
- 竟态条件:因为时序问题,而导致程序异常,我们称之为竟态条件。
2.3条件变量函数
初始化:
参数:
cond:要初始化的条件变量
attr:NULL
销毁:
等待条件满足:
参数:
cond:要在这个条件变量上等待mutex:互斥量,后面详细讲
唤醒等待:
简单案例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>pthread_cond_t cond;
pthread_mutex_t mutex;void *r1(void *arg)
{while(1){pthread_cond_wait(&cond,&mutex);printf("活动\n");}
}void *r2(void *arg)
{while(1){pthread_cond_signal(&cond);sleep(1);}
}int main()
{pthread_t t1,t2;pthread_cond_init(&cond,NULL);pthread_mutex_init(&mutex,NULL);pthread_create(&t1,NULL,r1,NULL);pthread_create(&t2,NULL,r2,NULL);pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}
为什么pthread_cond_wait需要互斥量?
- 条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程
- 条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据
- 按照上面的说法,我们设计出如下的代码:先上锁,发现条件不满足,解锁,然后等待在条件变量上不就性了,如下代码:
//错误的设计
pthread_mutex_lock(&mutex);
while(condition_is_false)
{pthread_mutex_unlock(&mutex);//解锁之后,等待之间,条件可能已经满足,信号已经发出,但是该信号可能被错过pthread_cond_wait(&cond);pthread_mutex_lock(&mutex);
}
pthread_mutex_unlock(&mutex);
- 由于解锁和等待不是原子操作。调用解锁之后,pthread_cond_wait之前,如果已经有其他线程获取到互斥量,摒弃条件满足,发送了信号,那么pthread_cond_wait将错过这个信号,可能会导致线程永远阻塞在这个pthread_cond_wait。所以解锁和等待必须必须是一个原子·操作
进入该函数后,会去看条件量等于0不?等于,就把互斥量变成1,直到cond_wait返回,把条件量改成1,把互斥量恢复成原样。
2.4条件变量使用规范
等待条件代码:
pthread_mutex_lock(&mutex);
while(条件为假)pthread_cond_wait(cond,mutex);
修改条件
pthread_mutex_unlock(&mutex);
给条件发送信号代码:
pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);