unix/linux进程间的通信------信号量

信号量简介

           信号量是一个计数器,用于进程和线程之间同步问题,也用于对临界资源访问问题。临界资源可以是一段代码或一个参数等。信号量值大于等于0,表示可访问临界资源的进程,小于0表示等待使用临界资源的进程。即为信号量是大于等于或小于0的数,赋予某个进程或线程访问或执行某段程序或调用某个参数的权限。

信号量的相关函数

           创建信号量

int semget(key_t key, int nsems, int semflg);

                        参数:

                                key:键值

                                nsems:创建信号量集中信号量的个数,只在创建信号量时有用

                                semflg:

                                                0:获取信号量级标识,若不存在,则报错

                                                IPC_CREAT:不存在创建信号量,存在则返回

                                                IPC_EXCL:与IPC_CREAT连用,若不存在,则创建,存在则报错 

                          返回值:

                                        成功执行返回信号量标识符,失败返回-1

                          创建信号量受到系统信息的影响

                                SEMMNI:系统中信号量的总数最大值

                                SEMMSL:每个信号量中信号量元素的个数最大值

                                SEMMNS:系统中素有信号量中的信号量元素的总数最大值

           信号量初始化

int semctl(int semid, int semnum, int cmd, ...);

                        参数:

                                semid:信号量标识

                                semnum:信号量集数组的下标,表示某一个信号

                                cmd:

                                        IPC_STAT从信号量集上检索semid_ds结构,并存到semun联合体参数的

                                        成员buf的地址中

                                        IPC_SET设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从

                                        semun的buf中取出值

                                        IPC_RMID从内核中删除信号量集合

                                        GETALL从信号量集合中获得所有信号量的值,并把其整数值存到semun

                                        联合体成员的一个指针数组中

                                        GETNCNT返回当前等待资源的进程个数

                                        GETPID返回最后一个执行系统调用semop()进程的PID

                                        GETVAL返回信号量集合内单个信号量的值

                                        GETZCNT返回当前等待100%资源利用的进程个数

                                        SETALL与GETALL正好相反

                                        SETVAL用联合体中val成员的值设置信号量集合中单个信号量的值

                        union semun

                                              {

                                                  short val; /*SETVAL用的值*/

                                                  struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/

                                                   unsigned short* array; /*SETALL、GETALL用的数组值*/

                                                   struct seminfo *_buf; /*为控制IPC_INFO提供的缓存*/

                                                }

                        struct semid_ds   

                                                     { 
                                                    struct ipc_perm sem_perm;     //权限相关信息 
                                                    time_t sem_otime;                   //最后一次semop()的信息 
                                                    tien_t sem_ctime;                    //最后一次状态改变时间 
                                                    unsigned short sem_nsems;    //信号量元素个数 
                                                     }

                        返回值:

                                        成功执行返回-1,失败返回-1

           PV操作

int semop(int semid, struct sembuf *sops, unsigned nsops);

                        参数:

                                semid:信号量标识符

                                nsops:结果体数组元素个数(有多个信号时创建,需操作时,使用数组分配操

                                作,此处为操作信号的个数)

                                sops:

                                         struct sembuf 
                                                                  {
                                                                        short semnum; /*信号量集合中的信号量编号,0代表

                                                                                                第1个信号量*/
                                                                         short val;
                                                                                       /*
                                                                                        l>0:V操作信号量值加val,进程释放控制

                                                                                        的资源 
                                                                                        <0:P操作信号量值减val,(semval-val)

                                                                                         <0(semval为该信号量值),则调用进程阻塞
                                                                                        IPC_NOWAIT:不会睡眠,进程直接返回

                                                                                        EAGAIN错误
                                                                                        =0:阻塞等待信号量为0,调用进程进入睡

                                                                                        眠状态,直到信号值为0
                                                                                        IPC_NOWAIT:进程不会睡眠,直接返回

                                                                                        EAGAIN错误
                                                                        short flag;  /*
                                                                                        0;设置信号量的默认操作
                                                                                        IPC_NOWAIT:设置信号量操作不等待
                                                                                        SEM_UNDO:内核记录调用进程的UNDO

                                                                                        记录,进程崩崩溃,根据UNDO记录恢复信号

                                                                                          量的计数值
                                                                                             */
                                                                                        }

                        返回值:

                                        成功执行返回0,失败返回-1

demo1:

                1.创建父子进程

                2.子进程获取信号执行权限,打印son,归还权限

                3.父进程获取信号执行权限,打印father,归还权限

代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun 
{
        int             val;    
        struct semid_ds *buf;    
        unsigned short  *array;  
        struct seminfo  *__buf;  
};

void get_atu(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;
        sops.sem_op = 1;
        sops.sem_flg = SEM_UNDO;
        semop(semid,&sops,1);
}

void return_atu(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;
        sops.sem_op = -1;
        sops.sem_flg = SEM_UNDO;
        semop(semid,&sops,1);
}

void result()
{
        key_t key;
        int semid;
        int pid;
        key = ftok(".",128);
        if(key == -1)
        {
                printf("create key fail\n");
                perror("why");
                exit(-1);
        }
        semid = semget(key,1,IPC_CREAT|0777);
        if(semid == -1)
        {
                printf("create sign fail\n");
                perror("why");
                exit(-1);
        }
        union semun init_sign;
        init_sign.val = 0;
        semctl(semid,0,SETVAL,init_sign);
        pid = fork();
        if(pid == 0)
        {
                get_atu(semid);
                printf("son\n");
                return_atu(semid);
        }
        else if(pid > 0)
        {
                get_atu(semid);
                printf("father\n");
                return_atu(semid);
        }
        else
        {
                printf("create fork fail\n");
                perror("why");
                exit(-1);
        }
}

int main()
{
        result();
        return 0;
}

结果示例:

 

demo2:

                1.编写程序,创建共享内存,写入hello word

                2.编写程序,获得权限信号,读取共享内存,释放权限

代码示例:

                create_shm

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

void result()
{
                key_t key;
                int shmid;
                char *context = "hello word";
                char *shmaddr = NULL;
                key = ftok(".",128);
                if(key == -1)
                {
                                printf("crate key fail\n");
                                perror("why");
                                exit(-1);
                }
                shmid = shmget(key,20,IPC_CREAT|0777);
                if(shmid == -1)
                {
                                printf("crate show memory fail\n");
                                perror("why");
                                exit(-1);
                }
                shmaddr = shmat(shmid,0,0);
                if(shmaddr == NULL)
                {
                                printf("show memory mappingfail\n");
                                perror("why");
                                exit(-1);
                }
                strcpy(shmaddr,context);
                sleep(10);
                shmctl(shmid,IPC_RMID,NULL);
                shmdt(shmaddr);
}

int main()
{
                result();
                return 0;
}

signal_shm

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

union semun 
{
                int              val;    
                struct semid_ds *buf;    
                unsigned short  *array;  
                struct seminfo  *__buf;  
};

void get_key(int semid)
{
                struct sembuf sops;
                sops.sem_num = 0;
                sops.sem_op = 2;
                sops.sem_flg = SEM_UNDO;
                semop(semid,&sops,1);
}

void return_key(int semid)
{
                struct sembuf sops;
                sops.sem_num = 0;
                sops.sem_op = -2;
                sops.sem_flg = SEM_UNDO;
                semop(semid,&sops,1);
}

void read_shm(int key)
{
                int shmid;
                char *shmaddr = NULL;
                shmid = shmget(key,20,IPC_CREAT|0777);
                shmaddr = shmat(shmid,0,0);
                printf("show memory : %s\n",shmaddr);
                shmctl(shmid,IPC_RMID,NULL);
}

void    result()
{
                key_t key;
                int semid;
                key = ftok(".",128);
                if(key == -1)
                {
                                printf("create key fail\n");
                                perror("why");
                                exit(-1);
                }
                semid = semget(key,1,IPC_CREAT|0777);
                union semun init_sem;
                init_sem.val = -1;
                semctl(semid,0,SETVAL);
                get_key(semid);
                read_shm(key);
                return_key(semid);
}

int main()
{
                result();
                return 0;
}

结果示例:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值