线程间的互斥与同步
生产者消费者问题(用于理解线程间互斥与同步的典型事例)
线程间互斥:对于临界资源区,同一时刻只能由一个线程访问。相当于仓库,生产好的产品入库时,就不能从仓库中取东西;从仓库中取东西时,就不能将生产好的产品入库。
线程间同步:有些线程需要有次序的运行,这时候就要用到进程间同步。相当于仓库,只有在仓库中的产品数量大于0时,从仓库中取产品的操作才能进行;只有在仓库中的产品数量小于总数时,新产品入库的操作才能进行。
线程间互斥:互斥锁
线程间同步:信号量
/*************************************************************************
> File Name: pv.c
> Author: LiYongjun
> Mail: 1160606604@qq.com
> Created Time: Mon 25 Feb 2019 02:10:47 PM CST
************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
pthread_mutex_t mutex; //互斥锁,用于互斥,保护临界资源,同一时刻只能有一人操作仓库
sem_t empty, full; //信号量,用于同步,生产者消费者问题
int sum;
void *t1_fun(void *arg)
{
while(1)
{
sem_wait(&full); //full - 1
pthread_mutex_lock(&mutex); //上锁
sum--;
printf("thread 1, sum = %d\n", sum);
sleep(1);
pthread_mutex_unlock(&mutex); //解锁
sem_post(&empty); //wait + 1
}
}
void *t2_fun(void *arg)
{
while(1)
{
sem_wait(&empty); //empty - 1
pthread_mutex_lock(&mutex); //上锁
sum++;
printf("thread 2, sum = %d\n", sum);
sleep(3);
pthread_mutex_unlock(&mutex); //解锁
sem_post(&full); //full + 1
}
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&mutex, NULL); //初始化互斥量
sem_init(&empty, 0, 5); //初始化信号量
sem_init(&full, 0, 0);
pthread_t t1, t2;
pthread_create(&t1, NULL, t1_fun, NULL);
pthread_create(&t2, NULL, t2_fun, NULL);
while(1)
{
sleep(10);
}
}
执行结果
[root@VM_0_14_centos test]# gcc pv.c -lpthread
[root@VM_0_14_centos test]# ./a.out
thread 2, sum = 1
thread 2, sum = 2
thread 2, sum = 3
thread 2, sum = 4
thread 2, sum = 5
thread 1, sum = 4
thread 1, sum = 3
thread 1, sum = 2
thread 1, sum = 1
thread 1, sum = 0
thread 2, sum = 1
thread 2, sum = 2
thread 2, sum = 3
thread 2, sum = 4
thread 2, sum = 5
可以看到,仓库中产品的数量永远介于0~5之间(5为仓库最大容量)。
注解:
1.互斥锁
pthread_mutex_init()
函数原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
pthread_mutex_init()函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为空,则使用默认的互斥锁属性,默认属性为快速互斥锁 。
pthread_mutex_lock()
当pthread_mutex_lock()返回时,该互斥锁已被锁定。线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。
pthread_mutex_unlock()
pthread_mutex_unlock()可释放mutex引用的互斥锁对象。
2.信号量
sem_init()
原型:int sem_init(sem_t *sem, int pshared, unsigned int value);
sem :指向信号量对象
pshared : 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享。
value : 指定信号量值的大小
sem_wait()
sem_wait是一个函数,也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,将信号量的值将减到1。
如果对一个值为0的信号量调用sem_wait(),这个函数就会原地等待直到有其它线程增加了这个值使它不再是0为止。
sem_post()
sem_post是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同 时对同一个文件进行读和写操作的两个程序就有可能会引起冲突。
- 点赞
- 收藏
- 关注作者
评论(0)