购物网站建设需求模板开发网站需要哪些技术
购物网站建设需求模板,开发网站需要哪些技术,全国前十名校程序开发公司,wordpress语法线程安全主要分为两个方面#xff0c;分别是资源访问互斥与线程同步#xff08;线程协同配合#xff09;
本篇博客#xff0c;我们主要来讲解资源访问互斥这一方面
目录
为什么要实现资源访问互斥#xff1f;
实现资源访问互斥#xff08;原子访问#xff09;的经典…线程安全主要分为两个方面分别是资源访问互斥与线程同步线程协同配合
本篇博客我们主要来讲解资源访问互斥这一方面
目录
为什么要实现资源访问互斥
实现资源访问互斥原子访问的经典机制——互斥锁
互斥锁相关函数
使用互斥锁实现资源访问互斥的具体实现
代码实现
结果图示 为什么要实现资源访问互斥
我们来做一个情景假设 假设现在有两个线程分别是线程A和线程B有一个全局变量名为numnum的初始值位0。 现在这两个线程都要对num这个全局变量进行1操作并且都得到了时间片大家觉得结果一定是2吗 还真不一定为什么呢我来通过几条汇编指令来给大家讲解一下 首先我们要知道 num num 1 ; 这条语句在计算机中的汇编语言是如何实现的 mov eax , num #将num的数值放入寄存器eax中add eax , 1 #将寄存器eax中的数值1mov num , eax #再将eax中的数值赋给num 假设线程A和线程B同时获得了num的初始值也就是他们的第一条汇编指令是同时进行的不论后续两步谁快谁慢num最后的结果都是1因为他们寄存器中num的数值都是0。只有两个线程先后进行对num数值的修改才能够得到正确的结果2
为什么会出现这种情况呢就是因为他们没实现对资源的原子访问两个线程互相将对方的结果覆盖了。所以我们要采用方法杜绝这种情况实现资源访问互斥让两个线程对这些共享数据实现原子访问。也就是当自己对这些共享数据进行读写的时候其余线程不可以对这些数据进行读写操作
实现资源访问互斥原子访问的经典机制——互斥锁
实现原子访问的经典机制之一便是互斥锁机制。要理解互斥锁机制我们可以拿身边最常见的一个东西来进行举例那就是卫生间
我做一个情景假设来帮助大家理解互斥锁机制 假设现在陆续有十个人要来上厕所卫生间只有一个 第一个人到了尝试开卫生间的门其实也就是尝试获取卫生间门锁的使用权发现门没有被锁上于是获得了卫生间门锁的使用权锁上了卫生间的门并使用卫生间第二个人到了尝试开卫生间的门发现门被锁上了于是排在第一个等待卫生间开门其他的人到了尝试开卫生间的门发现门被锁上了排在第一个人后面等待卫生间开门第一个人出来了对卫生间的门进行解锁卫生间现在可供一个人使用排在队伍的第一个人获得了卫生间门锁的使用权锁上了卫生间的门并使用卫生间后面的步骤同上 卫生间就好比数据卫生间的门锁就好比互斥锁。 每个线程要想使用这些共享数据就要先尝试获取互斥锁如果发现卫生间门锁被锁上也就是该互斥锁正在被使用的话这些线程就会进入资源等待队列等待这个锁的使用权等到该互斥锁可以使用了排在最前面的线程就会得到该锁并对需要访问的共享资源进行上锁从而正确使用这些共享资源 PS: 相同共享资源的互斥锁只能有一把如果有多把互斥锁每个线程都可以拿着互斥锁对共享资源进行上锁的话互斥锁的存在就没有意义了线程间的共享资源包括全局资源全局变量就属于全局资源的一种、文件描述符、进程信息、堆区空间、信号行为、库空间等在互斥锁保护区间的代码也被称为临界区代码临界区代码越简短越好否则会影响工作效率拿到互斥锁的线程在解锁后可能会再次拿到互斥锁不是一个线程只能拿一次 如果还是不能够理解的话我们仍旧拿上面的那两个线程举例并和上面的情景进行比对
假设现在有两个线程分别是线程A和线程B要对初始值位0的全局变量num进行加一操作步骤如下
步骤卫生间情景线程情景①第一个人到了尝试获取卫生间门锁的使用权发现门没有被锁上于是获得了卫生间门锁的使用权锁上了卫生间的门并使用卫生间线程A到了尝试获取互斥锁发现锁没有被使用于是获得了该锁的使用权并对全局变量num进行上锁操作②第二个人到了尝试开卫生间的门发现门被锁上了于是排在第一个等待卫生间开门线程B到了尝试获取互斥锁但是锁只有一把于是便进入资源等待队列等待该锁的使用权③第一个人出来了对卫生间的门进行解锁卫生间门锁现在可供一个人使用线程A对全局变量num的1操作完成对该互斥锁进行解锁操作锁现在可以被一个线程使用④第二个人获得了卫生间门锁的使用权锁上了卫生间的门并使用卫生间线程B获得了该互斥锁的使用权并对全局变量num进行上锁操作⑤第二个人出来了对卫生间的门进行解锁卫生间被使用了两次 情景完成线程B对全局变量num的1操作完成对该互斥锁进行解锁操作num的结果为2情景完成
以上大致就是实现互斥锁机制的具体过程了接下来我们来了解以下相关函数
互斥锁相关函数
这里我们要用到一个结构体叫做pthread_mutex_t这是互斥锁的相关结构体
先介绍下一会会用到的几个变量
pthread_mutex_t lock ; //定义一个互斥锁的结构体const pthread_mutexattr_t attr ; //锁属性相关结构体使用默认属性就直接传NULL
函数功能返回值pthread_mutex_init(lock , attr);实现互斥锁的初始化成功完成之后会返回0其他任何返回值都表示出现了错误pthread_mutex_destroy(lock);释放锁资源所占用的内存成功返回0失败返回错误编号pthread_mutex_lock(lock);上锁成功返回0失败返回错误编号pthread_mutex_unlock(lock);解锁成功返回0失败返回错误编号
使用互斥锁实现资源访问互斥的具体实现
在了解了相关函数和实现资源互斥访问的情况下我们来写一段小代码来实现一个功能
两个线程各对全局变量num加5000次每次加1 难度⭐⭐
PS要注意的是不是每个线程一次加满5000次才让另一个线程再加5000次而是两个线程轮流加最后都能加满5000次
代码实现
//mutex_lock.c#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/wait.h
#include sys/stat.h
#include signal.h
#include pthread.h
#include fcntl.h//将次数定义成宏
#define CONT 5000//将互斥锁与num定义成全局变量来让两个线程都可以获取该锁和num
pthread_mutex_t lock;
int num 0;//两个线程的工作是一样的所以这里只用定义一个工作函数
void* thread_job(void* arg)
{int i 0;pthread_detach(pthread_self());//将线程设置为分离态让系统自己回收//对num进行循环1操作//注意不要把锁加在循环外面如果放在外面就代表着让一个线程一次性加满5000次后再让另一个线程加//如果把锁家在循环外面两个线程的工作效率还不如单线程工作效率高while(i CONT){pthread_mutex_lock(lock);//上锁//这就是临界区代码在上锁与解锁之间的代码就是临界区代码num; i;printf(thread No.0x%x num , num %d\n , (unsigned int)pthread_self() , num);pthread_mutex_unlock(lock);//解锁}pthread_exit(NULL);
}int main()
{//初始化互斥锁pthread_mutex_init(lock , NULL);pthread_t tids[2];//创造线程A和线程Bpthread_create(tids[0] , NULL , thread_job , NULL);pthread_create(tids[1] , NULL , thread_job , NULL);//让主线程循环睡眠来让线程A和线程B获取时间片//由于我们把线程设置成了分离态系统会自动回收线程不用我们操心while(1){sleep(1);}//回收锁资源pthread_mutex_destroy(lock);exit(0);
}
结果图示 我们可以发现以上代码实现了该功能并完成了我们的要求没有让一个线程一次性加满五千次在加到9310的时候就发生了一次线程转换 以上就是本篇博客的全部内容了大家有什么地方没有看懂的话可以在评论区留言给我咱要力所能及的话就帮大家解答解答
今天的学习记录到此结束啦咱们下篇文章见ByeBye
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/88564.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!