线程安全访问之互斥量、死锁和条件变量

今天,我们来说说互斥量和条件变量的API

线程安全

因为进程中的线程共享了进行的虚拟地址空间,因此,线程间的通信变得更加简单,但是缺点也随之而来。这个缺点是:缺少数据的安全访问控制,容易造成数据混乱。因此,我们必须使用互斥量和条件变量来维持数据的安全访问。
我们把能造成数据混乱的情况总结了一个比较经典的模型:它们都是描述了多个线程/进程之间在数据访问时候所应保持的关系。使得不会出现数据混乱和逻辑混乱问题。

生产者消费者模型

因此提出了同步与互斥,互斥量来解决线程间的互斥问题,条件变量来解决线程间的同步问题。

互斥量

临界资源是需要受保护的。互斥量是用来实现线程间的互斥操作,具体用到是互斥锁。互斥锁也是一个临界资源,所有的线程均要访问它,互斥锁本身就是一个原子操作。
实现线程间的互斥操作API;
1、定义一个互斥锁:

pthread_mutex_t mutex;//定义了一个叫做mutex的互斥锁

2、初始化互斥锁:

静态初始化互斥锁。

//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//静态初始化的互斥锁不需要释放。

动态初始化互斥锁。

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//mutex:互斥锁名称,即上面定义的mutex
//attr:初始化互斥锁属性,通常置为NULL
//动态初始化的互斥锁需要释放。

3、对临界资源进行加锁、解锁

加锁:

int pthread_mutex_lock(pthread_mutex_t *mutex);//该函数为阻塞加锁,即没有锁资源时,一直等待直到有锁资源时加锁。
//mutex:上面初始化的mutex(锁)

int pthread_mutex_trylock(pthread_mutex_t *mutex);//该函数为非阻塞加锁,即没有锁资源时,不等待直接报错返回。
//mutex:上面初始化的mutex(锁)

解锁:

int pthread_mutex_unlock(pthread_mutex_t *mutex);
//mutex:上面初始化的mutex(锁)

4、释放互斥锁:

int pthread_mutex_destroy(pthread_mutex_t *mutex);
//mutex:上面初始化的mutex(锁)

对互斥锁进行操作时,有加锁就一定要有解锁,并且必须在任意一个有可能退出的地方都要进行解锁操作。否则会造成其他线程的锁死。

死锁

死锁:多个线程对锁资源进行竞争访问。但是因为线程推进顺序不当,导致相互等待。使得线程无法继续往下运行。
死锁情况:因为一直获取不到锁资源而造成的锁死情况。
死锁产生的必要条件:必须具备条件才能满足。
1、互斥条件----A线程获取了锁资源,B线程就不能获取该锁资源。
2、请求与保持条件----A线程在拿到第一个锁之后又去获取第二把锁,在没有获取到第二把锁之前不释放第一把锁。
3、不可剥夺条件----A线程获取了一把锁,其他线程不能释放A线程所获取到的这把锁。
4、环路等待条件----A线程拿了锁1去请求锁2,B线程拿了锁2去请求锁1
预防产生死锁:破幻死锁产生的必要条件。
死锁避免:死锁检查算法,银行家算法。

条件变量

条件变量是实现同步的机制。条件变量实现了等待+唤醒的操作机制。操作条件不满足则等待,别人促使条件满足了则唤醒等待队列上的线程。
线程在对临界资源访问之前,先判断临界资源是否能够操作,若可以则线程直接操作,若不能操作,则条件变量提供等待功能,让该线程pcb等待在条件变量等待队列上。

使用条件变量有以下步骤:
1、定义条件变量:

pthread_cond_t cond//定义一个叫做cond的条件变量。

2、条件变量初始化

静态初始化条件变量:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态初始化的条件变量不需要手动释放。

动态初始化条件变量:

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//cond:定义的条件变量名称。
//attr:条件变量的属性。
//动态初始化的条件变量需要手动释放。

3、线程在判断出条件不满足的情况下提供等待功能:

等待abstime秒还不满足时,报错返回:

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
//cond:条件变量名称。
//:mutex:互斥锁名称。
//timespec:一个结构体,两个成员分别是秒和纳秒。

阻塞等待:

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//cond:条件变量名称。
//mutex:互斥锁名称。

4、用户在促使条件满足后的,唤醒等待队列上的线程。

唤醒等待队列上的全部线程:

int pthread_cond_broadcast(pthread_cond_t *cond);
//cond:条件变量名称。

唤醒等待队列上的最早进来的第一个线程:

int pthread_cond_signal(pthread_cond_t *cond);
//cond:条件变量名称。

5、销毁条件变量:

pthread_cond_destroy(&cond);
//cond:条件变量名称。

你可能感兴趣的:(系统编程,互斥量,条件变量,死锁)