信号量与其他进程间的通信方式不大相同,主要用途是保护临界资源。进程可以根据它判断是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。
二值信号量:信号量的值只能取0或1,类似于互斥锁。但两者有不同:信号量强调共享资源,只要共享资源可用,其他进程同样可以修改信号量的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。
计数信号量:信号量的值可以取任意非负值。
#include
#include
#include
int semget(key_t key,int nsems,int flags)
成功返回信号集ID,失败返回-1
int semop(int semid,struct sembuf *sops,size_t nops);
对信号量进行控制。
成功返回0,失败返回-1
sembuf的定义如下:
struct sembuf{
short sem_num; //除非使用一组信号量,否则它为0
short sem_op; //信号量在一次操作中需要改变的数据,通常是两个数,
//一个是-1,即P(等待)操作,
//一个是+1,即V(发送信号)操作。
short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号量,
//并在进程没有释放该信号量而终止时,操作系统释放信号量
};
int semctl(int semid,int semnum,int cmd, ...);
如有需要第四个参数一般设置为union semnu arg;定义如下:
union semun
{
int val; //使用的值
struct semid_ds *buf; //IPC_STAT、IPC_SET 使用的缓存区
unsignedshort *arry; //GETALL,、SETALL 使用的数组
struct seminfo *__buf;// IPC_INFO(Linux特有) 使用的缓存区
};
SETVAL:用来把信号量初始化为一个已知的值。p 这个值通过union semun中的val成员设置,其作用是在信号量第一次使用前对它进行设置。
IPC_RMID:用于删除一个已经无需继续使用的信号量标识符,删除的话就不需要缺省参数,只需要三个参数即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
static int sem_id = 0;
static int set_semvalue()
{
//用于初始化信号量,在使用信号量前必须这样做
union semun sem_union;
sem_union.val = 1;
if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
return 0;
return 1;
}
static void del_semvalue()
{
//删除信号量
union semun sem_union;
if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphore\n");
else
fprintf(stdout, "已经删除信号量\n");
}
static int semaphore_p()
{
//对信号量做减1操作,即等待P(sv)
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return 0;
}
return 1;
}
static int semaphore_v()
{
//这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed\n");
return 0;
}
return 1;
}
int main(int argc, char *argv[])
{
char message = 'S';
int i = 0;
//创建信号量
sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
if(argc > 1)
{
//程序第一次被调用,初始化信号量
if(!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore\n");
exit(EXIT_FAILURE);
}
//设置要输出到屏幕中的信息,即其参数的第一个字符
message = argv[1][0];
sleep(2);
}
cout< 1)
{
//如果程序是第一次被调用,则在退出前删除信号量
sleep(3);
del_semvalue();
}
exit(EXIT_SUCCESS);
}
编译运行:
[root@192 semaphore]# g++ semaphore.cpp -o semaphore
[root@192 semaphore]# ./semaphore 1
21
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
进入1离开1
1913 - finished
已经删除信号量
[root@192 semaphore]#
部分参考:https://blog.csdn.net/qq_30168505/article/details/53041825#