i.MX6ULL终结者进程间通信System V信号灯

信号灯也叫信号量,它能够用来同步进程的动作,不能传输数据。它的应用场景就像红绿灯,控制各进程使用共享资源的顺序。Posix无名信号灯用于线程同步, Posix有名信号灯,System V 信号灯。本章讨论用于进程同步的System V信号灯。
信号灯相当于一个值大于或等于0计数器,信号灯值大于0,进程就可以申请资源,信号灯值-1,如果信号灯值为0,一个进程还想对它进行-1,那么这个进程就会阻塞,直到信号灯值大于1。
使用System V信号灯的步骤如下:
1.使用semget()创建或打开一个信号灯集。
2.使用semctl()初始化信号灯集,。
3.使用semop()操作信号灯值,即进行 P/V操作。
P操作:申请资源,申清完后信号灯值-1;
V操作:释放资源,释放资源后信号灯值+1;
常用的API如下:
semget()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

函数功能:创建新信号灯集或获取一个创建好的信号灯集。
参数含义:
key:通过ftok()获取的key值;
nsems:指定信号灯集合中信号灯的数量;
semflg:权限掩码,指定IPC_CREAT为如果没有则创建该信号灯集,指定IPC_EXCL为如果存 在返回错误。
返回值:成功返回信号灯集标识符id,失败返回-1,

semctl():初始化信号灯集合
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

   int semctl(int semid, int semnum, int cmd, .../* union semun arg*/);

参数含义:
semid:信号灯集标识符;
semnum:要操作的集合中的信号灯编号
cmd:执行的操作 SETVAL IPC_RMID
arg :cmd指定SETVAL命令后由此参数向集合中的单个信号量赋值。

semop():在信号量上执行一个或多个操作。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

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

参数含义:
semid:信号灯集标识符;
sops:指向数组的指针,数组成员是对信号灯操作的结构体;
struct sembuf {
unsigned short sem_num; /信号量索引/
short sem_op; /* 执行的操作,+1或-1 /
short sem_flg; /
,阻塞0,不阻塞IPC_NOWAIT */
}
nsops:数组大小,最小是1。
返回值:成功返回0,失败返回-1。
实验代码在shm_sem/目录下:路径为:11_Linux系统开发进阶\Linux系统编程_章节使用资料。
write进程向共享内存写数据,read进程从共享内存读数据,使用信号灯同步,先写再读,read进程读完阻塞,等待write进程将S_READ信号进行V操作。
信号灯相关函数在“sem.h”:

#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
 
#define S_READ  0
#define S_WRITE 1
 
union semun
{
    int value;
};
 
/*声明两种操作方式*/
struct sembuf sop[2]; 
 
/*
 * P操作,申请资源,信号量值-1
 */
void p_ipc_sem(int index,int semid)
{
    sop[0].sem_num = index;
    sop[0].sem_op = -1;//信号量值-1
    sop[0].sem_flg = 0;//阻塞
    semop(semid,&sop[0],1);
}
 
 
/*
 * V操作,释放资源,信号量值+1
 */
void v_ipc_sem(int index,int semid){
    sop[1].sem_num = index;
    sop[1].sem_op = 1;//信号量值+1
    sop[1].sem_flg =0;//阻塞
    semop(semid,&sop[1], 1);
}

sem.h文件中union semun用于初始化信号量,p_ipc_sem和v_ipc_sem用于P/V操作。
向共享内存写数据的程序在write.c中:

#include "sem.h"
 
int main(int argc, char const *argv[])
{
    int ret;
    key_t key;
    int sem_id;
    int shmid;
    union semun u_u;
    char *shmaddr;
 
    key = ftok("./",808);
    if(key == -1){
        perror("ftok");
        return -1;
    }
    sem_id= semget(key,2,IPC_CREAT | 0666);//申请两个信号量
    if(sem_id < 0){
        perror("semget");
        return -2;
    }
    
    /*
     * 初始化信号量
     */
    u_u.value = 0;
    ret = semctl(sem_id,S_READ,SETVAL,u_u);
    if (ret < 0)
    {
        perror("semctl");
        return -3;
    }
    u_u.value = 1;
    ret = semctl(sem_id,S_WRITE,SETVAL,u_u);
    if (ret < 0)
    {
        perror("semctl");
        return -3;
    }
    shmid = shmget(key,256,IPC_CREAT|0666); //申请共享内存
    shmaddr = (char *)shmat(shmid, NULL, 0);   //映射到程序的地址空间
 
    while(1){
        //P操作:
        //通过信号量,读进程释放资源,索引为S_WRITE的信号量值+1,
        //写进程才能获取资源,S_WRITE信号量值-1,
        //这里的资源是指共享内存。
        p_ipc_sem(S_WRITE,sem_id);
 
        printf("写进程PID<%d>输入:--->\n",getpid());
        fgets(shmaddr,32,stdin);//从终端获取数据并写入共享内存
 
        //V操作:
        //写进程释放资源S_READ+1,读进程才能拿到资源,然后读进程S_READ-1。
        v_ipc_sem(S_READ,sem_id);
    }
         
    return 0;
}

读进程在read.c中:

#include "sem.h"
 
int main(int argc, const char *argv[])
{
    int ret;
    key_t key;
    int sem_id;
 
    key = ftok("./",808);
    if(key == -1){
        perror("ftok");
        return -1;
    }
    sem_id= semget(key,2,IPC_CREAT | 0666);
    if(sem_id < 0){
        perror("semget");
        return -2;
    }
    int shmid;
    shmid = shmget(key,256,IPC_CREAT|0666); //申请共享内存
    char *shmaddr;
    shmaddr = (char *)shmat(shmid, NULL, 0);   //映射到程序的地址空间
     
    while(1){
        p_ipc_sem(S_READ,sem_id);
        printf("读进程PID<%d>接收到:%s\n",getpid(),shmaddr);
        v_ipc_sem(S_WRITE,sem_id);
    }
 
    return 0;
}

执行make编译:
在这里插入图片描述

图 1

使用两个终端进行实验,一个运行写进程,一个运行读进程,在写进程输入数据,效果如下:
在这里插入图片描述

图 2

发现能够读出写到共享内存的数据,使用“ipcs”命令观察IPC对象:
在这里插入图片描述

图 3

信号灯和共享内存的简单用法介绍到这里。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值