《UNIX网络编程 卷2》 笔记: 使用FIFO实现信号量
来源:互联网 发布:辐射4女角色捏脸数据 编辑:程序博客网 时间:2024/06/04 23:32
上节我们给出的例子使用的都是基于内存的信号量,还有一种信号量是有名信号量。两者的关系就像管道和FIFO一样。有趣的是,有名信号量可以使用FIFO来实现。具体思想是:每个有名信号量和一个FIFO关联,FIFO中数据的字节数代表该信号量的值。sem_post函数往该FIFO中写入一个字节,sem_wait函数从FIFO中读出一个字节。
我们自己实现的信号量类型mysem_t定义如下:
typedef struct {/*FIFO读和写描述符*/int sem_fd[2];int sem_magic;} mysem_t;#define SEM_MAGIC0x89674532#define MYSEM_FAILED ((mysem_t *)(-1))
它包含FIFO读写端描述符和一个表示信号量的魔数。
创建或打开一个有名信号量的实现函数如下:
mysem_t* mysem_open(const char *pathname, int oflag, ...){int i, flags, save_errno;char c;va_list ap;mode_t mode;unsigned int value;mysem_t *sem;if (oflag & O_CREAT) { /*如果指定O_CREAT标志,文件不存在则会创建文件*/va_start(ap, oflag);mode = va_arg(ap, mode_t);value = va_arg(ap, unsigned int);va_end(ap);/*创建FIFO*/if (mkfifo(pathname, mode) < 0) {/*如果返回EEXIST错误,但没有指定O_EXCL标志,忽略该错误*/if (errno == EEXIST && (oflag & O_EXCL) == 0)oflag &= ~O_CREAT;elsereturn MYSEM_FAILED;}}/*分配内存*/if ((sem = malloc(sizeof(mysem_t))) == NULL)return MYSEM_FAILED;sem->sem_fd[0] = sem->sem_fd[1] = -1;/*以非阻塞读的方式打开FIFO*/if ((sem->sem_fd[0] = open(pathname, O_RDONLY | O_NONBLOCK)) < 0)goto error;/*以非阻塞写的方式打开FIFO*/if ((sem->sem_fd[1] = open(pathname, O_WRONLY | O_NONBLOCK)) < 0)goto error;/*将FIFO读描述符改为阻塞*/if ((flags = fcntl(sem->sem_fd[0], F_GETFL, 0)) < 0)goto error;flags &= ~O_NONBLOCK;if (fcntl(sem->sem_fd[0], F_SETFL, flags) < 0)goto error;if (oflag & O_CREAT) {/*写入value字节数据*/for (i = 0; i < value; i++)if (write(sem->sem_fd[1], &c, 1) != 1)goto error;}sem->sem_magic = SEM_MAGIC;return sem;error:/*保存出错时的errno*/save_errno = errno;if (oflag & O_CREAT)unlink(pathname);close(sem->sem_fd[0]);close(sem->sem_fd[1]);free(sem);errno = save_errno;return MYSEM_FAILED;}/*包裹函数*/mysem_t* MySem_open(const char *pathname, int oflag, ...){ va_list ap; mode_t mode; unsigned int value; mysem_t *sem; va_start(ap, oflag); mode = va_arg(ap, mode_t); value = va_arg(ap, unsigned int); va_end(ap); if ((sem = mysem_open(pathname, oflag, mode, value)) == MYSEM_FAILED) err_sys("mysem_open error"); return sem;}
每次打开一个有名信号量,我们打开它关联的FIFO两次,一次是为了读,一次是为了写。第一次我们使用非阻塞读的方式打开该FIFO是为了避免进程被阻塞(详见FIFO这一节 图4-21),后面我们又调用fcntl将打开的读描述符设置为阻塞的方式。
出错处理时我们先保存errno的值,因为后面的系统调用可能改变它的值。
关闭有名信号量和删除有名信号量的实现函数如下:
int mysem_close(mysem_t *sem){if (sem->sem_magic != SEM_MAGIC) {errno = EINVAL;return -1;}sem->sem_magic = 0;/*关闭FIFO*/if (close(sem->sem_fd[0]) == -1 || close(sem->sem_fd[1]) == -1) {free(sem);return -1;}free(sem);return 0;}int mysem_unlink(const char *pathname){/*删除FIFO*/return unlink(pathname);}
挂起一个有名信号量和等待一个有名信号量的实现函数如下:
int mysem_post(mysem_t *sem){char c;if (sem->sem_magic != SEM_MAGIC) {errno = EINVAL;return -1;}if (write(sem->sem_fd[1], &c, 1) == 1)return 0;return -1;}int mysem_wait(mysem_t *sem){char c;if (sem->sem_magic != SEM_MAGIC) {errno = EINVAL;return -1;}if (read(sem->sem_fd[0], &c, 1) == 1)return 0;return -1;}mysem_post函数往FIFO中写入1字节数据,给信号量的值加1。它不会阻塞。
mysem_wait函数从FIFO中读出1字节数据,给信号量的值减1。当信号量的值为0(FIFO中没有数据)时,它就会阻塞直到信号量的值大于0(FIFO中有数据)。
阅读全文
0 0
- 《UNIX网络编程 卷2》 笔记: 使用FIFO实现信号量
- 《UNIX网络编程 卷2》 笔记: FIFO
- 《UNIX网络编程 卷2》 笔记: 使用内存映射I/O实现信号量
- 《UNIX网络编程 卷2》 笔记: Posix信号量
- UNIX网络编程卷二 笔记 管道和FIFO
- unix网络编程卷2:管道和FIFO
- UNIX网络编程卷二 笔记 Posix信号量
- 《UNIX网络编程 卷2》 笔记: 读写锁及其实现
- 《UNIX网络编程 卷2》 笔记: 使用内存映射I/O实现消息队列
- 《UNIX网络编程 卷2》 笔记: 简介
- 《UNIX网络编程 卷2》 笔记: 管道
- UNIX网络编程 卷2 源代码使用
- UNIX网络编程 卷2 源代码使用
- UNIX网络编程 卷2 源代码使用
- UNIX网络编程 卷2 源代码使用
- 【UNIX网络编程】FIFO
- unix网络编程----------fifo
- 互斥锁,条件变量,信号量的一个区别(unix网络编程卷2)
- cocos2dx luabinding C/C++/LUA部分
- 符号配对
- sublime text 3 教程(2)
- Java IO流
- 项目管理师基础背诵
- 《UNIX网络编程 卷2》 笔记: 使用FIFO实现信号量
- 【Python】【matplotlib】面向对象方式绘图
- Eclipse中的Maven项目报错处理方法
- svn安装,配置
- 安卓 三个绘图工具类详解
- Eclipse中的Maven项目报错处理方法
- 心酸的Caffe安装之路 环境搭配 Ubuntu16.04+gtx1080+cuda8.0+cudnn5.1+opencv+Anaconda3+caffe
- rapidjson使用总结
- gradle android的依赖配置dependencies