1、同步互斥的概念
在多任务操作系统中,同时运行的多个任务可能都需要访问或使用同一种资源多个任务之间有依赖关系,某个任务的运行依赖于另一个任务同步和互斥就是用于解决这两个问题的。
什么互斥:
一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共
资源。POSIX标准中进程和线程同步和互斥的方法,主要有信号量和互斥锁两种方式。
什么同步:
两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。
同步就是在互斥的基础上有顺序(注意不是同时执行)
要想完成上述顺序,需要借助信号量,实现同步操作
二、互斥锁
2.1、互斥锁的概念(mutex)
mutex是一种简单的加锁的方法来控制对共享资源的访问,mutex只有两种状态。即上锁(lock)和解锁(unlock)。
2.2、互斥锁的操作
2.2.1 初始化互斥锁
mutex用pthread_mutex_t数据类型表示,在使用互斥锁前,必须先对它进行初始化。
静态分配的互斥锁:(不常用)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
动态分配互斥锁:
pthread_mutex_t mutex; (在main上定义此类型)
pthread_mutex_init(&mutex, NULL); (在main下初始化)
在所有使用过此互斥锁的线程都不再需要使用时候,应调用pthread_mutex_destroy销毁
头文件:#include <pthread.h>
原型:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t
*mutexattr);
3 功能:初始化一个互斥锁
4 参数:5 mutex:指定的互斥锁
6 mutexattr:互斥锁的属性,为NULL表示默认属性
7 返回值:
8 成功:0
2.2.2 互斥锁上锁
1 头文件 : #include <pthread.h>
2 原型 :int pthread_mutex_lock(pthread_mutex_t *mutex);
3 功能 :对互斥锁上锁,若已经上锁,则调用者一直阻塞到互斥锁解锁
4 参数:
5 mutex:指定的互斥锁
6 返回值:
7 成功:0
8 失败:非0
2.2.3 互斥锁解锁
1头文件 : #include <pthread.h>
2 原型 :int pthread_mutex_unlock(pthread_mutex_t * mutex);
3 功能 :对指定的互斥锁解锁。
4 参数:
5 mutex:互斥锁地址。
6 返回值:
7 成功:0
8 失败:非0
2.2.4 销毁互斥锁
1头文件 : #include <pthread.h>
2 原型 : int pthread_mutex_destroy(pthread_mutex_t *mutex);
3 功能 :销毁指定的一个互斥锁。
4 参数:
5 mutex:互斥锁地址。
6 返回值:7 成功:0
8 失败:非0。
如果不使用互斥锁
案例1,一位富豪手里有两张卡,一张金卡,一张副卡。卡里面的余额只有10000元,于是派两名手下,个自拿一张卡去取钱。请问卡还有多少钱
如果不使用互斥锁,可以解决上述问题??--------不行
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int money = 10000;
void *pthread_fun1(void *arg)
{
int get, yu, shiji;
get = 10000;
printf("张三正在查询余额...\n");
sleep(1);
yu = money;
printf("张三正在取钱...\n");
sleep(1);
if(get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("张三想取%d元,实际取了%d元,余额为%d元\n", get, shiji, yu);
pthread_exit(NULL);
}
void *pthread_fun2(void *arg)
{
int get, yu, shiji;
get = 10000;
printf("李四正在查询余额...\n");
sleep(1);
yu = money;
printf("李四正在取钱...\n");
sleep(1);
if(get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("李四想取%d元,实际取了%d元,余额为%d元\n", get, shiji, yu);
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
pthread_t thread1, thread2;
if(pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if(pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
运行结果
张三正在查询余额...
李四正在查询余额...
张三正在取钱...
李四正在取钱...
张三想取10000元,实际取了10000元,余额为0元
李四想取10000元,实际取了10000元,余额为0元
由运行结果可知,答案是错误的
使用互斥锁,解决问题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//通过互斥锁解决线程间互斥问题
int money = 10000;
//第一步:创建互斥锁(由于两个线程操作同一个互斥锁,所以定义在全局更加方便一点)
pthread_mutex_t mymutex;
void *pthread_fun1(void *arg)
{
int get, yu, shiji;
get = 10000;
//第三步:对共享资源的操作进行上锁
pthread_mutex_lock(&mymutex);
printf("张三正在查询余额...\n");
sleep(1);
yu = money;
printf("张三正在取钱...\n");
sleep(1);
if(get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("张三想取%d元,实际取了%d元,余额为%d元\n", get, shiji, yu);
//第四步:当共享资源的操作执行完毕后,对互斥锁执行解锁操作
pthread_mutex_unlock(&mymutex);
pthread_exit(NULL);
}
void *pthread_fun2(void *arg)
{
int get, yu, shiji;
get = 10000;
//第三步:对共享资源的操作进行上锁
pthread_mutex_lock(&mymutex);
printf("李四正在查询余额...\n");
sleep(1);
yu = money;
printf("李四正在取钱...\n");
sleep(1);
if(get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("李四想取%d元,实际取了%d元,余额为%d元\n", get, shiji, yu);
//第四步:当共享资源的操作执行完毕后,对互斥锁执行解锁操作
pthread_mutex_unlock(&mymutex);
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
//第二步:初始化互斥锁
pthread_mutex_init(&mymutex, NULL);
pthread_t thread1, thread2;
if(pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if(pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//第五步:当互斥锁使用完毕后,要销毁
pthread_mutex_destroy(&mymutex);
return 0;
}
运行结果
张三正在查询余额...
张三正在取钱...
张三想取10000元,实际取了10000元,余额为0元
李四正在查询余额...
李四正在取钱...
李四想取10000元,实际取了0元,余额为0元
信号量的使用,请看下一节