信号量的作用是给共享内存加锁
信号量只允许进程进行等待和发送信号操作
通用信号量应用场景较少,一般使用二元信号量
信号量和互斥锁的原理是类似的
引用头文件
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
相关函数
1.初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
- sem:需要初始化的信号量。
- pshared:传入0值表示线程间共享,传入非零值表示进程间共享。
- value:信号量的初始值(计数器的初始值)。
返回值说明:
- 初始化信号量成功返回0,失败返回-1。
2.销毁信号量
int sem_destroy(sem_t *sem);
参数说明:
- sem:需要销毁的信号量。
返回值说明:
- 销毁信号量成功返回0,失败返回-1。
3.等待信号量(申请信号量)
int sem_wait(sem_t *sem);
参数说明:
- sem:需要等待的信号量。
返回值说明:
- 等待信号量成功返回0,信号量的值减一。
- 等待信号量失败返回-1,信号量的值保持不变。
4.发布信号量(释放信号量)
int sem_post(sem_t *sem);
参数说明
- sem:需要发布的信号量。
返回值说明:
- 发布信号量成功返回0,信号量的值加一。
- 发布信号量失败返回-1,信号量的值保持不变。
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <semaphore.h>
int main()
{
int shmky = ftok("./test1.cpp",'a'); //通过同一个文件生成相同的key,用于读取同一个内存
if(shmky<0){
perror("ftok");
return -2;
}
int shmid = shmget(shmky,128,0755|IPC_CREAT); //1.创建共享内存空间
if(shmid<0){
perror("shmget");
exit(1);
}
printf("shmget success %d\n",shmid); //创建的共享内存可用 ipcrm -m id删除
system("ipcs -m"); //调用内核,显示当前系统的共享内存
sem_t sem;
int sem_id = sem_init(&sem, 1, 1);
int pid = fork();//创建4个进程同时操作同一个共享内存
if(pid ==0)
{
int pid2 = fork();
if(pid2 ==0)
{
int* i = (int*)shmat(shmid,NULL,0); //将char类型数据关联到共享内存
sem_wait(&sem);
(*i)=0;
sem_post(&sem);
for(int x = 0;x<100;x++)
{
sem_wait(&sem);
printf("process1 i=%d\n",*i);
(*i)++;
sem_post(&sem);
}
shmdt(i);
} else{
int* i = (int*)shmat(shmid,NULL,0); //将char类型数据关联到共享内存
for(int x = 0;x<100;x++)
{
sem_wait(&sem);
printf("process2 i=%d\n",*i);
(*i)++;
sem_post(&sem);
}
shmdt(i);
}
}else{
int pid3 = fork();
if(pid3 ==0)
{
int* i = (int*)shmat(shmid,NULL,0); //将char类型数据关联到共享内存
for(int x = 0;x<100;x++)
{
sem_wait(&sem);
printf("process3 i=%d\n",*i);
(*i)++;
sem_post(&sem);
}
shmdt(i);
} else{
int* i = (int*)shmat(shmid,NULL,0); //将char类型数据关联到共享内存
for(int x = 0;x<100;x++)
{
sem_wait(&sem);
printf("process4 i=%d\n",*i);
(*i)++;
sem_post(&sem);
}
shmdt(i);
sleep(5);
sem_destroy(&sem);
shmctl(shmid,IPC_RMID,NULL);
}
}
}
要验证代码的话,将某个进程中的sem_post注释,即可发现程序会卡在该进程