非常非常非常.....的重要在共享内存的代码里面p1.c实质是有问题lt._flag = 1;//这里先置1if(c == 'Q')sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好,%d 我系渣渣辉. %d 是兄弟就来砍我吧!!! %d",i,i+1,i+2);while(*((int *)shmptr));//如果别人没有把上一条消息给拿走,那我就卡在这里memcpy(shmptr,&lt,sizeof(lt));//copy到共享内存  我们是想copy之后别人拿这个信息我们是想copy之后别人拿这个信息 --- copy之后你根本就没有告诉别人copy完是什么时候那么别人就可以在你copy中途的就过来拿p2 -> lt._flag等于1了就可以拿了lt._flag等于1是在copy的时间段里面前面那个时间就会将其置1p2看到变成1了,它就可以去读后面内容了,p2很有可能拿到了一个错误的内容现在我要解决这个问题lt._flag = 0;//if(c == 'Q')sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好,%d 我系渣渣辉. %d 是兄弟就来砍我吧!!! %d",i,i+1,i+2);while(*((int *)shmptr));//如果别人没有把上一条消息给拿走,那我就卡在这里memcpy(shmptr,&lt,sizeof(lt));//copy到共享内存  我们是想copy之后别人拿这个信息*(int *)shmptr = 1;//再置1又有一个新的问题出现了,出现了p3 也操作这个共享内存,它也是往这个共享内存里面写的p1正在写的途中,p3过来一看 _flag == 0它也可以写看谁搞得慢,谁慢就保留谁的信息上面不管有几个进程在活动,不变的只有一个 --- 共享内存不变那么我可以对这个共享内存实现一个保护机制 --- 只要有进程在操作这个共享内存,别人都不能操作int flag;//这个flag在共享内存上面,有别与上面共享内存每一个进程在放在共享内存的时候都先过来看看flag的值如果flag == 0 ,我就不能访问共享内存flag == 1,我就可以去访问,访问之前我先将flag调成0,然后访问共享内存访问完毕再调成1每一个进程在访问之前都过来看这个flag,都遵守这个规则,那么就不会出现问题了p1 和 p2同时过来看flag的值,他们两个同时发现flag == 1他们就去访问这个共享内存了,这个保护机制又崩溃了要将保护机制继续完善,谁过来访问flag的时候其它的人都不能访问如果你再弄一个保护的flag1,flag1又可能要成为保护的对象,这就成了一个死局了我们只需要解决不能同时过来操作flag的值 --- 原子操作可以解决(cpu产生的指令只会允许有一个进程过来操作)解决这个保护问题,并且实现原子操作的事情就是信号量解决的问题信号量就是一个以原子操作来实现的一个保镖保证我们的共享资源有序访问它是为了保护别人而生的,没有保护对象就不需要信号量信号量是一种保护机制,对程序员的一个约定(程序员应该遵守,不是强制,程序员要知道如果你不遵守,你很有可能得到一个错误的值)    因此在并发里面信号量机制成为了必然信号量的操作流程首先实现 P操作(上锁,上锁的过程是原子操作)上锁完毕,再过去访问共享资源共享资源访问完毕   -> 这个区域我们叫临界区(约定:快进快出)如果你占着这个临界区,结果你死了或者一直不进行V操作,这种情况我们叫死锁(死锁是一个非常严重的问题,我们不应该有死锁的操作)再进行 V操作(解锁)P操作:使其信号量递减的操作V操作:使其信号量递增的操作如我的flag = 1;P操作就是--flag;V操作就是++flagflag = 1 ->这种信号量我们叫互斥信号量 但是有的时候某一些共享资源支持多个进程同时访问,那么这个时候flag > 1P操作一般我们认为是 --就可以了,但是有的时候可能一个进程需要多个资源,这个时候就不是--,它需要 -= nV操作有的时候就需要 += n信号量实现 --- 它是实现在内核上面的一个标志,对于它的操作保证了原子操作信号量有两种System V semaphore  -> 两种标准 此标准一般用于进程System V信号量是一个信号量集,里面有多个信号量信号量集里面的信号量可以单独操作的,实现对于不同共享资源或者同一个共享资源需要多个信号量的保护的需求POSIX semaphore -> 此标准一般用于线程struct semid_ds {struct ipc_perm    sem_perm;     /* 权限 */__kernel_time_t    sem_otime;    /* 最后 semop 时间 */__kernel_time_t    sem_ctime;    /* 最后 semctl() 时间 */struct sem *sem_base;    /*信号量数组 */ = malloc(sizeof(struct sem) * nsems)struct sem_queue *sem_pending;    /* 等在这个信号量队列上面的进程 */struct sem_queue **sem_pending_last;   /* 最后等的那个 */struct sem_undo    *undo;       /* 撤销 */unsigned short sem_nsems;    /* 信号量的个数,就是 sem_base有多少个元素*/
};struct sem//单个信号量的类型
{int value;//信号量的值pid_t sempid;//最后一次进行p/v操作的进程idint semncnt;//使其增长的进程数量int semzcnt;//使其变成0的进程数量
};创建一个信号量集semget - get a System V semaphore set identifierSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);key:一个ipc key,如果你想操作同一个信号量,key必须一样nsems:这个信号量集里面你想有几个信号量,只有创建信号量集的时候有效打开的时候这个参数会被忽略这个数量一旦确定了,以后就不能改了semflg:标志IPC_CREAT | 权限   创建0打开一个信号量集返回值:成功返回信号集的id,失败返回-1,同时errno被设置The  values of the semaphores in a newly created set are indeterminate.新创建出来的信号量集里面的信号量的值是不确定的所以我们需要给这些信号量马上设置值NAMEsemctl - System V semaphore control operations控制这个信号量集
SYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(int semid, int semnum, int cmd, ...);semid:信号量集的idsemnum:信号量集里面有多个信号量,你现在要操作哪一个你是不是要给我指明从0开始   一直到 nsems - 1如果cmd表明的是操作所有的信号量,那么这个参数就被忽略了cmd:命令号IPC_STAT    复制IPC_SET     设置IPC_RMID    删除GETALL      获取所有GETVAL      获取一个SETALL      设置所有SETVAL      设置一个.........(arg):根据第三个命令号来,命令不一样,这个参数就会不一样cmd == GETALL: 获取所有的信号量的值因此第四个参数就需要弄一个什么样子的东西进去,用于保存所有的信号量的值我们需要用一个unsigned short arr[nsems];//原先创建的时候nsems是多少,这里就给多少semctl(semid,0,GETALL,arr);cmd == GETVAL : 获取单个信号量的值第二个参数为哪一个信号量第四个参数就被忽略了,获取到的值通过返回值返回给你unsigned short value = semctl(semid,2,GETVAL);//获取信号量集里面的第三个信号的值cmd == SETALL : 设置所有的信号量的值,第二个参数被忽略第四个参数就是unsigned short数组的首地址unsigned short arr[5] = {3,2,5,7,1};//你的信号量集里面有5个信号量semctl(semid,2,SETALL,arr);cmd == SETVAL : 设置某一个信号量的值第二个参数为哪一个信号量第四个参数就是一个int值int  value = 4;semctl(semid,1,SETVAL,value);//设置信号量集里面的第二个信号量的值为4cmd == IPC_STAT/IPC_SET  获取或者设置信号量集头节点的信息第四个参数就是struct semid_ds的指针,第二个参数会被忽略struct semid_ds buf;semctl(semid,0,IPC_STAT,&buf);//将头部信息弄到buf里面去buf里面改一些什么东西了,然后想将buf设置回去semctl(semid,0,IPC_SET,&buf);cmd == IPC_INFOstruct seminfo __buf;semctl(semid,0,IPC_INFO,&__buf);.......由于第四个参数比较多变,为了统一这个参数,可以按照如下共同体建立一个结构体什么时候用哪一个就行union semun {int              val;    /* Value for SETVAL */struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */unsigned short  *array;  /* Array for GETALL, SETALL */struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */};cmd == SETALL,你怎么用这个共同体给我解决union semun hehe;hehe.array = malloc(sizeof(unsigned short) * nsems);//nsems就是信号量的个数//将值赋值到这个数组里面去hehe.array[0] = 3;hehe.array[1] = 1;....hehe.array[nsems - 1] = n;semctl(semid,2,SETALL,hehe.array);SEMOP(2)                   Linux Programmer's Manual                  SEMOP(2)NAMEsemop, semtimedop - System V semaphore operationsSYNOPSIS#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>struct sembuf arr[3];......int semop(int semid, struct sembuf *sops, size_t nsops);semid:你要操作哪一个信号集sops:操作的信息  有下面的结构struct sembuf{unsigned short sem_num;  /* 你要操作信号量集里面的那一个信号量 */short          sem_op;   /* 信号量的操作 P/V */P就是让信号量的值递减V就是让信号量的值递增所以这里填负数就是 P   -3 -> 将信号量的值 -= 3所以这里填正数就是 V   +3 -> 将信号量的值 += 3short          sem_flg;  /* 操作标志 */0 -> 阻塞IPC_NOWAIT -> 非阻塞SEM_UNDO  撤销这个标志很有意义,当有这个标志之后内核就会关注这个进程如果进程没有解锁就退出了,内核就会将这个进程操作的信号量的值恢复到P之前 -- 防止带锁退出而出现的死锁问题};nsops:sops这个玩意儿是一个数组的首地址,因此我需要将数组的元素个数传进去可能操作多个信号量int semtimedop(int semid, struct sembuf *sops, size_t nsops,const struct timespec *timeout);//这个函数多了一个timeout的操作//表示限时等待semop这个函数如果是阻塞上锁,别人没有释放锁的时候,它是上不上去的,这个时候就会卡在semopsemtimedop给了一个时间,这个时间到了就不等了struct timespec {__kernel_time_t tv_sec;          /* 秒 */long       tv_nsec;      /* 纳秒 */};//假设你要等 1s 500000ns的时间struct timespec tp;clock_gettime(CLOCK_REALTIME,&tp);//获取现在的时间//往后等1s 500000ns的时间tp.tv_sec += 1;tp.tv_nsec += 500000;if(tp.tv_nsec > 1000000000)//进1了{tp.tv_sec++;tp.tv_nsec -= 1000000000;}semtimedop(,,,&tp);返回值:成功0,失败-1,同时errno被设置死锁问题:只能避免死锁,如果出现死锁你是你的代码有问题,我们需要需要解决这个bug如果有一个变量i = 1;进程1对这个i++;进程2对这个i--两个进程不知道什么时候会运行,请问,当两个进程都运行完一遍之后这个i的值为多少进程1对i的操作可以分为三步:1读取i的值放在自己的内存空间 2对内存进行++ 3将结果写入到i的内存空间(这三步是原子操作)进程2对i的操作可以分为三步:4读取i的值放在自己的内存空间 5对内存进行-- 6将结果写入到i的内存空间(这三步是原子操作)145623 -> 2123456 -> 1456123 -> 1412356 -> 0451236 -> 0POSIX semaphore -> 单个信号量有名信号量:内容在内核里面,在文件系统里面有一个名字因此可以用于不同的进程间或者线程间无名信号量:没有名字,因此只能通过遗传,因此只能用于有亲缘关系的进程间如果这个无名信号量存在于父进程的内存空间,当子进程拷贝过去之后,父子里面的信号量就变成两个了这个时候父进程就会操作父进程,子进程操作的就是子进程的,这样就起不到保护的作用了那么我们就需要让这个信号存在于共享内存里面 --- 这种操作明显很麻烦,不建议使用或者线程间有名信号量:需要创建或者打开
NAMEsem_open - initialize and open a named semaphoreSYNOPSIS#include <fcntl.h>           /* For O_* constants */#include <sys/stat.h>        /* For mode constants */#include <semaphore.h>sem_t *sem_open(const char *name, int oflag);//纯粹的打开一个信号量sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);//这个玩意可以打开或者创建一个信号量name:一个存在的路径名  这个路径名里面只能有一个 /,开头也是它"/hehe.sem"oflag:标志0 打开O_CREAT 创建标记mode:你创建的时候需要这个权限  0664value:创建的时候才会有值的设置,如果是打开一个信号量是没有值的设置的只有创建成功才会被设置进去返回值:成功返回一个sem_t指针,指向我们的信号量失败返回SEM_FAILED,同时errno被设置Link with -pthread.//链接这个库 pthread  因此编译的时候需要在后面加上 -lpthread无名信号量只能初始化
NAMEsem_init - initialize an unnamed semaphoreSYNOPSIS#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);sem:保存我们的信号量pshared:共享方式0 :进程的内部线程共享1 : 不同进程间的共享 ---- 这种不建议使用value:值成功0 失败-1Link with -pthread.P操作
NAMEsem_wait, sem_timedwait, sem_trywait - lock a semaphore 上锁SYNOPSIS#include <semaphore.h>int sem_wait(sem_t *sem);//等待版本 P操作int sem_trywait(sem_t *sem);//尝试版本  非阻塞 P操作int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);//限时等待版本 P操作sem:你要对哪个信号量进程P操作Link with -pthread.V操作
NAMEsem_post - unlock a semaphore  解锁SYNOPSIS#include <semaphore.h>int sem_post(sem_t *sem);sem:你要对哪个信号量进程P操作Link with -pthread.POSIX信号量的其它操作NAMEsem_getvalue - get the value of a semaphore获取信号量的值
SYNOPSIS#include <semaphore.h>int sem_getvalue(sem_t *sem, int *sval);sem:你要对哪个信号量进程进行操作sval:值写入到这个内存空间Link with -pthread.NAMEsem_close - close a named semaphore//关闭不是删除关闭有名信号量
SYNOPSIS#include <semaphore.h>int sem_close(sem_t *sem);sem:你要对哪个信号量进程进行操作Link with -pthread.NAMEsem_unlink - remove a named semaphore//删除一个有名信号量SYNOPSIS#include <semaphore.h>int sem_unlink(const char *name);name:路径名Link with -pthread.NAMEsem_destroy - destroy an unnamed semaphore销毁一个无名信号量
SYNOPSIS#include <semaphore.h>int sem_destroy(sem_t *sem);sem:你要销毁哪个无名信号量Link with -pthread.正式项目里面一旦发现是多个进程/线程对一个资源进行读写,那么我们就要保护

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93836.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93836.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93836.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Scikit-learn通关秘籍:从鸢尾花分类到房价预测

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 决策树/SVM/KNN算法对比 模型评估指标解析 读者收获&#xff1a;掌握经典机器学习全流程 …

rsync + inotify 数据实时同步

rsync inotify 数据实时同步 一、rsync简介 rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步&#xff0c; 支持本地复制&#xff0c;或者与其他SSH、rsync主机同步 二、rsync三种命令 Rsync的命令格式常用的有以下三种&#xff1a;&#…

Linux基础介绍-3——第一阶段

文章目录一、进程管理1.1 进程的基本概念1.2 常见管理命令1.3 进程优先级调整&#xff1a;nice 与 renice二、软件包管理三、防火墙管理四、shell脚本五、xshell链接kali一、进程管理 1.1 进程的基本概念 进程是程序的动态执行实例&#xff0c;每个进程都有唯一的 PID&#x…

python 可迭代对象相关知识点

1. 什么是可迭代对象 (Iterable) 在 Python 里&#xff0c;可迭代对象指的是&#xff1a; &#x1f449; 能够一次返回一个元素的对象&#xff0c;可以被 for 循环遍历。 常见的可迭代对象有&#xff1a; 序列类型&#xff1a;list、tuple、str集合类型&#xff1a;set、dict&a…

ijkplayer Android 编译

一、下载编译库文件1.1 编译库文件环境&#xff1a;ubuntu 20.04 版本liangtao:ffmpeg$lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal1.2 项目源码下载使用 git 下载 ijkplayer&#…

snn前向推理时间计算(处理器实现)

公式 Tinf(1−sparsity)number of synapsesnumber of sub-processorsSIMD ways T_{\text{inf}} \frac{(1-\text{sparsity})\times \text{number of synapses}} {\text{number of sub-processors}\times \text{SIMD ways}} Tinf​number of sub-processorsSIMD ways(1−sparsity…

Linux------《操作系统全景速览:Windows·macOS·Linux·Unix 对比及 Linux 发行版实战指南》

&#xff08;一&#xff09;常见操作系统&#xff08;system&#xff09;电脑&#xff1a;Windows,Macos,Linux,UnixWindows&#xff1a;微软公司开发的一款桌面操作系统&#xff08;闭源系统&#xff09;。版本有dos&#xff0c;win98&#xff0c;win NT&#xff0c;win XP , …

Three.js 初级教程大全

本文档旨在为初学者提供一个全面的 Three.js 入门指南。我们将从 Three.js 的基本概念开始&#xff0c;逐步介绍如何创建场景、添加物体、设置材质、使用光照和相机&#xff0c;以及如何实现简单的动画和交互。通过本教程&#xff0c;你将能够掌握 Three.js 的核心知识&#xf…

遥感领域解决方案丨高光谱、无人机多光谱、空天地数据识别与计算

一&#xff1a;AI智慧高光谱遥感实战&#xff1a;手撕99个案例项目、全覆盖技术链与应用场景一站式提升方案在遥感技术飞速发展的今天&#xff0c;高光谱数据以其独特的光谱分辨率成为环境监测、精准农业、地质勘探等领域的核心数据源。然而&#xff0c;海量的波段数据、复杂的…

(LeetCode 面试经典 150 题) 114. 二叉树展开为链表 (深度优先搜索dfs+链表)

题目&#xff1a;114. 二叉树展开为链表 思路&#xff1a;深度优先搜索dfs链表&#xff0c;时间复杂度0(n)。 C版本&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : …

《线程状态转换深度解析:从阻塞到就绪的底层原理》

目录 一、线程的五种基本状态 二、线程从 RUNNABLE 进入阻塞 / 等待状态的三种典型场景 1. 调用sleep(long millis)&#xff1a;进入 TIMED_WAITING 状态 2. 调用wait()&#xff1a;进入 WAITING/TIMED_WAITING 状态 3. 等待 I/O 资源或获取锁失败&#xff1a;进入 BLOCKE…

面经整理-猿辅导-内容服务后端-java实习

部门管理系统设计 题目要求 设计部门 MySQL 数据表实现接口&#xff1a;根据中间部门 ID 获取其下属叶子部门 ID设计包含子节点列表的 Java 数据对象&#xff0c;并实现批量获取功能 一、MySQL 部门表设计 表结构 CREATE TABLE department (id BIGINT PRIMARY KEY AUTO_INCREME…

Openharmony之window_manager子系统源码、需求定制详解

1. 模块概述 Window Manager 模块是 OpenHarmony 操作系统的核心窗口管理系统,负责窗口的创建、销毁、布局、焦点管理、动画效果以及与硬件显示的交互。该模块采用客户端-服务端架构,提供完整的窗口生命周期管理和用户界面交互支持。 1.1架构总览 Window Manager Client 应…

《CDN加速的安全隐患与解决办法:如何构建更安全的网络加速体系》

CDN&#xff08;内容分发网络&#xff09;作为提升网站访问速度的关键技术&#xff0c;被广泛应用于各类互联网服务中。然而&#xff0c;在享受加速优势的同时&#xff0c;CDN也面临诸多安全隐患。本文将解析常见的CDN安全问题&#xff0c;并提供实用的解决办法&#xff0c;帮助…

【Linux指南】GCC/G++编译器:庖丁解牛——从源码到可执行文件的奇幻之旅

不只是简单的 gcc hello.c 每一位Linux C/C++开发者敲下的第一行编译命令,几乎都是 gcc hello.c -o hello 或 g++ hello.cpp -o hello。这像一句神奇的咒语,将人类可读的源代码变成了机器可执行的二进制文件。但在这条简单的命令背后,隐藏着一个如同精密钟表般复杂的多步流…

地区电影市场分析:用Python爬虫抓取猫眼_灯塔专业版各地区票房

在当今高度数据驱动的影视行业&#xff0c;精准把握地区票房表现是制片方、宣发团队和影院经理做出关键决策的基础。一部电影在北上广深的表现与二三线城市有何差异&#xff1f;哪种类型的电影在特定区域更受欢迎&#xff1f;回答这些问题&#xff0c;不能再依赖“拍脑袋”和经…

Spark03-RDD02-常用的Action算子

一、常用的Action算子 1-1、countByKey算子 作用&#xff1a;统计key出现的次数&#xff0c;一般适用于K-V型的RDD。 【注意】&#xff1a; 1、collect()是RDD的算子&#xff0c;此时的Action算子&#xff0c;没有生成新的RDD&#xff0c;所以&#xff0c;没有collect()&…

[Android] 显示的内容被导航栏这挡住

上图中弹出的对话框的按钮“Cancel/Save”被导航栏遮挡了部分显示&#xff0c;影响了使用。Root cause: Android 应用的主题是 Theme.AppCompat.Light1. 修改 AndroidManifest.xml 将 application 标签的 android:theme 属性指向新的自定义主题&#xff1a;<applicationandr…

分贝单位全指南:从 dB 到 dBm、dBc

引言在射频、音频和通信工程中&#xff0c;我们经常会在示波器、频谱仪或测试报告里看到各种各样的dB单位&#xff0c;比如 dBm、dBc、dBV、dBFS 等。它们看起来都带个 dB&#xff0c;实则各有不同的定义和参考基准&#xff1a;有的表示相对功率&#xff0c;有的表示电压电平&a…

怎么确定mysql 链接成功了呢?

asyncio.run(test_connection()) ✗ Connection failed: cryptography package is required for sha256_password or caching_sha2_password auth methods 根据你提供的错误信息,问题出现在 MySQL 的认证插件和加密连接配置上。以下是几种解决方法: 1. 安装 cryptography 包…