int semop(int semid ,struct sembuf *sops ,size_t nsops);
//用户改变信号量的值。也就是使用资源还是释放资源使用权
包含头文件:
include<sys/sem.h>
参数:
semid : 信号量的标识码。也就是semget()的返回值
sops是一个指向结构体数组的指针。
struct sembuf{
unsigned short sem_num;//信号灯编号;
short sem_op;//对该信号量的操作。‐1 ,P操作,1 ,V操作
short sem_flg;0阻塞,1非阻塞
};
sem_op : 操作信号灯的个数
//如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;
如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于
或等于sem_op的绝对值。
通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
#define SEM_READ 0
#define SEM_WRITE 1
union semnum
{
int val;
};
void Poperation(int index,int semid)
{
struct sembuf sop;
sop.sem_num = index;
sop.sem_op = -1;
sop.sem_flg = 0;
semop(semid,&sop,1);
}
void Voperation(int index,int semid)
{
struct sembuf sop;
sop.sem_num = index;
sop.sem_op = 1;
sop.sem_flg = 0;
semop(semid,&sop,1);
}
int main()
{
key_t key;
key = ftok(".",123);
pid_t pid;
int semid;
int shmid;
char *shmaddr;
semid = semget(key,2,IPC_CREAT|0755);
if(semid < 0)
{
perror("semget");
return -1;
}
shmid = shmget(key,128,IPC_CREAT|0755);
if(shmid < 0)
{
perror("shmget");
return -2;
}
//init semapuore
union semnum myun;
//init semaphore read
myun.val = 0;
semctl(semid,SEM_READ,SETVAL,myun);
//init semaphore write
myun.val = 1;
semctl(semid,SEM_WRITE,SETVAL,myun);
pid = fork();
if(pid == 0)
{
shmaddr = (char *)shmat(shmid,NULL,0);
while(1)
{
Poperation(SEM_READ,semid);
printf("get share memory is:%s\n",shmaddr);
Voperation(SEM_WRITE,semid);
}
}
if(pid > 0)
{
shmaddr = (char *)shmat(shmid,NULL,0);
while(1)
{
Poperation(SEM_WRITE,semid);
printf("please input to share memory\n");
fgets(shmaddr,32,stdin);
Voperation(SEM_READ,semid);
}
}
return 0;
}

union共用体:semctl 初始化专用
- 语法:
union共用体:所有成员共用一块内存,这里只存一个 int 值
- 知识点:
Linux 规定:用semctl(SETVAL)给信号量设初值,必须传这个共用体
- 逻辑:
专门用来装「信号量初始计数器数值」
代码整套逻辑
- ftok 造一把钥匙 → 信号量 + 共享内存绑定
- semget 造 2 个红绿灯,shmget 造一块黑板
- semctl 初始化:写灯亮 (1),读灯灭 (0)
- fork 拆成父子两人
- 父:抢写灯→写黑板→开读灯喊子
- 子:等读灯亮→读黑板→开写灯喊父
- P = 等牌卡死,V = 放牌唤醒