追风赶月莫停留,平芜尽处是春山。这篇文章主要讲述Linux系统编程POSIX有名信号量相关的知识,希望能为你提供帮助。
00. 目录
文章目录
- 00. 目录
- 01. 概述
- 02. 相关函数
- 2.1 创建有名信号量
- 2.2 关闭有名信号量
- 2.3 删除有名信号量
- 2.4 信号量P操作
- 2.5 信号量V操作
- 03. 程序示例
- 04. 附录
01. 概述 在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥。它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。
02. 相关函数 2.1 创建有名信号量
#include <
fcntl.h>
/* For O_* constants */
#include <
sys/stat.h>
/* For mode constants */
#include <
semaphore.h>
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,
mode_t mode, unsigned int value);
Link with -pthread.
功能:
创建一个有名信号量。
参数:
name:信号量文件名。注意,不能指定路径名。因为有名信号量,默认放在/dev/shm 里
flags:sem_open() 函数的行为标志。
mode:文件权限(可读、可写、可执行)的设置。
value:信号量初始值。
返回值:
成功:信号量的地址
失败:SEM_FAILED
2.2 关闭有名信号量
#include <
semaphore.h>
int sem_close(sem_t *sem);
Link with -pthread.
功能:
关闭有名信号量。
参数:
sem:指向信号量的指针。
返回值:
成功:0
失败:-1
2.3 删除有名信号量
#include <
semaphore.h>
int sem_unlink(const char *name);
功能:
删除有名信号量的文件。
参数:
name:有名信号量文件名。
返回值:
成功:0
失败:-1
2.4 信号量P操作
#include <
semaphore.h>
int sem_wait(sem_t *sem);
功能:
将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,
此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。
参数:
sem:信号量的地址。
返回值:
成功:0
失败: - 1int sem_trywait(sem_t *sem);
? 以非阻塞的方式来对信号量进行减 1 操作。
? 若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
? 限时尝试将信号量的值减 1
? abs_timeout:绝对时间
abs_timeout补充说明
struct timespec {
time_t tv_sec;
/* seconds */ // 秒
longtv_nsec;
/* nanosecondes*/ // 纳秒
}time_t cur = time(NULL);
//获取当前时间。
struct timespec t;
//定义timespec 结构体变量t
t.tv_sec = cur + 1;
// 定时1秒
sem_timedwait(&
cond, &
t);
2.5 信号量V操作
#include <
semaphore.h>
int sem_post(sem_t *sem);
功能:
将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。
参数:
sem:信号量的地址。
返回值:
成功:0
失败:-1
03. 程序示例 示例一:有名信号量实现进程间互斥功能
#include<
stdio.h>
#include<
semaphore.h>
#include<
fcntl.h>
#include<
unistd.h>
#include<
sys/stat.h>
#include<
sys/types.h>
void printer(sem_t *sem, char *str)
{
sem_wait(sem);
//信号量减一
while(*str!=\'\\0\')
{
putchar(*str);
fflush(stdout);
str++;
sleep(1);
}
printf("\\n");
sem_post(sem);
//信号量加一
}
int main(int argc, char *argv[])
{
pid_t pid;
sem_t *sem = NULL;
pid = fork();
//创建进程
if(pid<
0){ //出错
perror("fork error");
}else if(pid == 0){ //子进程
//跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量
sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1);
//信号量值为 1
if(sem == SEM_FAILED){ //有名信号量创建失败
perror("sem_open");
return -1;
}char *str1 = "hello";
printer(sem, str1);
//打印sem_close(sem);
//关闭有名信号量_exit(1);
}else if(pid >
0){ //父进程//跟open()打开方式很相似,不同进程只要名字一样,那么打开的就是同一个有名信号量
sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1);
//信号量值为 1
if(sem == SEM_FAILED){//有名信号量创建失败
perror("sem_open");
return -1;
}char *str2 = "world";
printer(sem, str2);
//打印sem_close(sem);
//关闭有名信号量wait(pid, NULL);
//等待子进程结束
}
sem_unlink("name_sem");
//删除有名信号量
return 0;
}
测试结果:
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out
hello
world
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$
示例二: 有名信号量实现进程间同步功能(print2 先打印,再到 print1 打印)
【Linux系统编程POSIX有名信号量】print1.c 代码如下
#include <
fcntl.h>
/* For O_* constants */
#include <
sys/stat.h>
/* For mode constants */
#include <
semaphore.h>
#include <
stdio.h>
void print(sem_t *print1, sem_t *print2)
{
int i = 0;
while(1)
{
sem_wait(print1);
i++;
printf("int print1 i = %d\\n", i);
sem_post(print2);
}
}
int main(int argc, char **argv)
{
sem_t *print1, *print2;
print1 = sem_open("sem_print1", O_CREAT, 0777, 0);
if(SEM_FAILED == print1)
{
perror("sem_open");
}
print2 = sem_open("sem_print2", O_CREAT, 0777, 1);
if(SEM_FAILED == print2)
{
perror("sem_open");
}
print(print1, print2);
return 0;
}
print2.c 代码
#include <
fcntl.h>
/* For O_* constants */
#include <
sys/stat.h>
/* For mode constants */
#include <
semaphore.h>
#include <
stdio.h>
void print(sem_t *print1, sem_t *print2)
{
int i = 0;
while(1)
{
sem_wait(print2);
i++;
printf("in print2 i = %d\\n", i);
sleep(1);
sem_post(print1);
}
}
int main(int argc, char **argv)
{
sem_t *print1, *print2;
print1 = sem_open("sem_print1", O_CREAT, 0777, 0);
if(SEM_FAILED == print1)
{
perror("sem_open");
}
print2 = sem_open("sem_print2", O_CREAT, 0777, 1);
if(SEM_FAILED == print2)
{
perror("sem_open");
}
print(print1, print2);
return 0;
}
删除有名信号量的代码:
#include <
semaphore.h>
#include <
stdio.h>
void sem_del(char *name)
{
int ret;
ret = sem_unlink(name);
if(ret <
0)
{
perror("sem_unlink");
}
}
int main(int argc, char **argv)
{
sem_del("sem_print1");
//删除信号量文件sem_print1
sem_del("sem_print2");
//删除信号量文件sem_print2
return 0;
}
04. 附录
推荐阅读
- Linux系统编程Linux进程调度
- 重磅!博睿数据通过CMMI5级评估,国内APM领域首家
- Linux系统编程进程间通信之无名管道
- shell 中实现多行或两行合并成一行实现方法
- 测试图片
- Prometheus监控运维实战八(可视化)
- Linux基础kiickstart无人值守安装
- 在js,wordpress中移动CSS类时,使用insertafter复制CSS类
- 使用Elementor的高级自定义字段