文章目录

序言

提示:以下是本篇文章正文内容,下边案例可供参考

本文参考:%257B%2522request%255Fid%2522%253A%25226780261921257%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=6780261921257&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-4-86276502.pc_search_result_control_group&utm_term=linux+%E4%BF%A1%E5%8F%B7%E9%87%8F&spm=1018.2226.3001.4187

一、信号量简介:

在对于临界区资源管理的过程中,多个程序同时访问一个共享资源时常容易引起一系列问题:如死锁,结果不惟一等等,

在1965年,由法国科学家E.W.Dijkstra提出了一种新的进程同步工具,讯号量及其PV操作。

对于讯号量的定义

让多个进程通过特殊变量展开交互linux查看信号量命令,一个进程在某一个关键点上被迫停止执行直到接收到对应的特殊变量值,通过这一举措,任何复杂的进程交互要求均可得到满足,这些特殊的变量就是讯号量。

讯号量的种类通常讯号量

设s为一个记录型数据结构,其中value为整型变量,系统初始化时为其形参,PV操作的谓词描述如下:

P(s):将讯号量value值减1,若结果大于0,则执行P操作的进程被阻塞,若结果小于等于0,则执行P操作的进程将继续执行。

V(s):将讯号量的值加1,若结果不小于0,则执行V操作的进程从讯号量s有关的list所知队列中释放一个进程,使其转化为就绪态,自己则继续执行,若结果小于0,则执行V操作的进程继续执行。

二值讯号量:

设s为一个记录型数据结构,其中份量value仅能取值0或1,二值讯号量的PV操作的谓词描述和通常讯号量相同,即使二值讯号量仅能取值0或1,但可以证明他有着与其他讯号量相同的抒发能力。

二、编程实现

对于与讯号量操作有关的插口,Linux下主要提供了以下几个函数,值得注意的是,在Linux下的C插口中,这种函数的操作对象都是讯号量值组,也就是一个讯号量值的数组

1、ftok函数生成通配符

每一个共享储存段都有一个对应的通配符(key)相关联(消息队列、信号量也同样须要)。

所需头文件:#include

函数原型:key_tftok(constchar*path,intid);

所需头文件:#include<sys/ipc.h>
函数原型 :key_t ftok(const char *path ,int id);

path为一个已存在的路径名

id为0~255之间的一个数值,代表项目ID,自己取

返回值:成功返回通配符(相当于32位的int)。出错返回-1

比如:key_tkey=ftok(“/tmp”,66);

2、semget函数创建讯号量

所需头文件:
	   #include 
       #include 
       #include 
       
函数原型:int semget(key_t key, int num_sems, int sem_flags);

该函数的作用是创建一个新讯号量或取得一个已有讯号量。

第一个参数key是整数值(惟一非零),就是Linux线程操作中常常用到的通配符,可以通过ftok函数得到,不相关的进程可以通过它访问一个讯号量,它代表程序可能要使用的某个资源,程序对所有讯号量的访问都是间接的,程序先通过调用semget函数并提供一个键linux查看信号量命令,再由系统生成一个相应的讯号标示符(semget函数的返回值),只有semget函数才直接使用讯号量键,所有其他的讯号量函数使用由semget函数返回的讯号量标示符。假如多个程序使用相同的key值,key将负责协调工作。

第二个参数num_sems指定须要的讯号量数量,它的值几乎总是1。

第三个参数sem_flags是一组标志,当想要当讯号量不存在时创建一个新的讯号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,虽然给出的键是一个已有讯号量的键,也不会形成错误。而IPC_CREAT|IPC_EXCL则可以创建一个新的,惟一的讯号量,假如讯号量已存在,返回一个错误。

semget函数成功返回一个相应讯号标示符(非零),失败返回-1

2.semop函数:改变讯号量的值

所需头文件:
       #include 
       #include 

linux查看信号量命令_linux命令查看密码_linux命令大全 查看端口

#include int semop(int sem_id, struct sembuf *sops, size_t nsops);

该函数的作用是改变讯号量的值,虽然就是为了讯号量的PV操作而打算的,这个函数可以讲的地方比较多,下边会详尽介绍:

函数的第一个参数semid为讯号量集的标示符;

第2个参数sops指向进行操作的结构体字段的首地址,在semop的第二个参数sops指向的结构体链表中,每位sembuf结构体对应一个特定讯号的操作。因而对讯号量进行操作必须熟悉该数据结构,该结构定义在linux/sem.h,结构体如下:

struct sembuf{  
unsigned short sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号  
short sem_op; //操作类型  
short sem_flg; //操作标志  
}; 

对于该结构中各个成员都具有特殊的含意,具体含意的介绍如下:

sem_op参数:

sem_op>0讯号加上sem_op的值,表示进程释放控制的资源;

sem_op=0假如sem_flg没有设置IPC_NOWAIT,则调用进程步入睡眠状态,直至讯号量的值为0;否则进程不会睡眠,直接返回EAGAIN

sem_op<0讯号加上sem_op的值。若没有设置IPC_NOWAIT,则调用进程阻

塞,直至资源可用;否则进程直接返回EAGAIN

sem_flg参数:

该参数可设置为IPC_NOWAIT或SEM_UNDO两种状态。只有将sem_flg指定为SEM_UNDO标志后64位linux,semadj(所指定讯号量针对调用进程的调整值)就会更新。据悉,假若此操作指定SEM_UNDOlinux服务器维护,系统更新过程中会撤销此讯号灯的计数(semadj)。此操作可以随时进行—它永远不会强制等待的过程。调用进程必须有改变讯号量集的权限。

sem_flg公认的标志是IPC_NOWAIT和SEM_UNDO。若果操作指定SEM_UNDO,当该进程中止时它将会手动撤掉。

第3个参数nsops强调即将进行操作的讯号的个数。semop函数调用成功返回0,失败返回-1。

该函数所做的对于讯号量的操作都是原子操作,即整个行为是一个整体,是不可打断的。所有操作是否可以立刻执行取决于在个人sem_flg领域的IPC_NOWAIT标志的存在。

semctl函数讯号量的初始化和删掉

所需头文件:
       #include 
       #include 
       #include 
int semctl(int sem_id, int sem_num, int command, ...);

intsemctl(intsem_id,intsem_num,intcommand,[unionsemunsem_union]);

command:有两个值SETVAL,IPC_RMID,分别表示初始化和删掉讯号量。

sem_union:可选参数,结构如下:

union semun{  
    int val; 
    struct semid_ds *buf;  
    unsigned short *arry;  
}; 

函数的第一个参数semid为讯号量集的标示符;

函数的第二个参数sem_num则是表示即即将进行操作的讯号量的编号,即讯号量集合的索引值,其中第一个讯号量的索引值为0。

函数的第3个参数command代表即将在集合上执行的命令,其取值涵义如下,一般用特定的宏取代:

IPC_STAT:获取某个讯号量集合的semid_ds结构,并将其储存在semun联合体的buf参数所指的地址之中

linux命令查看密码_linux查看信号量命令_linux命令大全 查看端口

IPC_SET:设置某个集合的semid_ds结构的ipc_perm成员的值,该命令所取的值是从semun联合体的buf参数中取到的

IPC_RMID:从内核删掉该讯号量集合

GETALL:用于获取集合中所有讯号量的值,整数值储存在无符号短整数的一个链表中,该字段有联合体的array成员所指定

GETNCNT:返回当前正在等待资源的进程的数量

GETPID:返回最后一次执行PV操作(semop函数调用)的进程的PID

GETVAL:返回集合中某个讯号量的值

GETZCNT:返回正在等待资源借助率达到百分之百的进程的数量

SETALL:把集合中所有讯号量的值,设置为联合体的array成员所包含的对应值

SETVAL:将集合中单个讯号量的值设置为联合体的val成员的值

总结

提示:这儿对文章进行总结:

#include
#include
#include
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};
int sem_id;
int set_semvalue()
{
    union semun sem_union;    
    sem_union.val = 1;
    if(semctl(sem_id,0,SETVAL,sem_union)==-1)
        return 0;
    return 1;
}
int semaphore_p()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(sem_id,&sem_b,1)==-1)
    {
        fprintf(stderr,"semaphore_p failedn");
        return 0;
    }
    return 1;
}
int semaphore_v()
{

linux命令大全 查看端口_linux查看信号量命令_linux命令查看密码

struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; sem_b.sem_flg = SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { fprintf(stderr,"semaphore_v failedn"); return 0; } return 1; } void del_semvalue() { //删除信号量 union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union)==-1) fprintf(stderr,"Failed to delete semaphoren"); } int main(int argc,char *argv[]) { char message = 'x'; //创建信号量 sem_id = semget((key_t)1234,1,0666|IPC_CREAT); if(argc>1) { //初始化信号量 if(!set_semvalue()) { fprintf(stderr,"init failedn"); exit(EXIT_FAILURE); } //参数的第一个字符赋给message message = argv[1][0]; } int i=0; for(i=0;i<5;i++) { //等待信号量 if(!semaphore_p()) exit(EXIT_FAILURE); printf("%c",message); fflush(stdout); sleep(1); //发送信号量

if(!semaphore_v()) exit(EXIT_FAILURE); sleep(1); } printf("n%d-finishedn",getpid()); if(argc>1) { //退出前删除信号量 del_semvalue(); } exit(EXIT_SUCCESS); }

#include 
#include
#include 
#include 
void pGetKey(int semId)//p操作获取钥匙
{
	struct sembuf set;
	set.sem_num = 0;
	set.sem_op=-1;
	set.sem_flg = SEM_UNDO ;
	semop(semId,&set,1);
	printf("pGetKeyn");
}
void vPutbacKey(int semId)//v操作放回钥匙
{
	struct sembuf set;
	printf("vPutKeyn");
	set.sem_num = 0;
	set.sem_op=1;
	set.sem_flg = SEM_UNDO ;
	semop(semId,&set,1);
}
// struct sembuf{  
// unsigned short sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号  

// short sem_op; //操作类型 // short sem_flg; //操作标志 // }; union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int main(int argc, char const *argv[]) { key_t key; key = ftok("./" ,66); int semId; //int semget(key_t key, int num_sems, int sem_flags); semId = semget(key,1,IPC_CREAT|0666); if(semId == 1) { printf("creat error!n"); } union semun initsem; initsem.val = 0; semctl( semId, 0, SETVAL , initsem); int pid = fork(); if(pid > 0) { pGetKey(semId); printf("this is father!n"); vPutbacKey(semId); } else if(pid == 0) { printf("this is child!n"); vPutbacKey(semId); }else{ printf("creat process error!n"); } return 0; }

本文原创地址:https://www.linuxprobe.com/xhlwzzwbcz.html编辑:刘遄,审核员:暂无