0. 信号量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char * argv[]){
fork();
int i=0;
for(;i<5;i++){
printf("PID:%d,enter\n",getpid());
sleep(1);// do something
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
}
}
数据竞争
-
来源
- 分类
根据共享资源的数目可分为二值信号量和计数信号量两类。
No. |
分类 |
取值 |
e.g. |
1 |
二值信号量 |
0 和1
|
指示锁 |
2 |
计数信号量 |
0 和n
|
停车场电子牌 |

指示锁

停车场电子指示牌

信号量
No. |
分类 |
取值 |
1 |
P(信号量) |
0 :挂起进程;>0 :减1 |
2 |
V(信号量) |
0 :恢复进程;>0 :加1 |
- 本质
任一时刻只能有一个进程访问临界区(代码),数据更新的代码。
1. POSIX 信号量
- 资料:
unpv22e-ch10.1~10.13
- 查看:
man sem_overview
1.1 接口
1.2 函数
1.2.1 命名信号量/基于文件
No. |
操作 |
函数 |
1 |
创建 |
sem_t *sem_open(const char *name, int oflag, mode_t mode,unsigned int value) |
2 |
删除 |
int sem_unlink(const char *name) |
3 |
打开 |
sem_t *sem_open(const char *name, int oflag) |
4 |
关闭 |
int sem_close(sem_t *sem) |
5 |
挂出 |
int sem_post(sem_t *sem) |
6 |
等待 |
int sem_wait(sem_t *sem) |
7 |
尝试等待 |
int sem_trywait(sem_t *sem) |
8 |
获取信号量的值 |
int sem_getvalue(sem_t *sem, int *sval) |
1.2.1.1 创建
sem_t *sem_open(const char *name, int oflag, mode_t mode,unsigned int value)
No. |
参数 |
含义 |
1 |
name |
信号量IPC名字 |
2 |
oflag |
标志 |
3 |
mode |
权限位 |
4 |
value |
信号量初始值 |
IPC名字有什么要求?
No. |
返回值 |
含义 |
1 |
非SEM_FAILED
|
信号量的指针 |
2 |
SEM_FAILED |
出错 |
1.2.1.2 删除
int sem_unlink(const char *name)
No. |
参数 |
含义 |
1 |
name |
信号量IPC名字 |
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.1.3 打开
sem_t *sem_open(const char *name, int oflag)
No. |
参数 |
含义 |
1 |
name |
信号量IPC名字 |
2 |
oflag |
标志 |
No. |
返回值 |
含义 |
1 |
非SEM_FAILED
|
信号量的指针 |
2 |
SEM_FAILED |
出错 |
1.2.1.4 关闭
int sem_close(sem_t *sem)
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.1.5 挂出
int sem_post(sem_t *sem)
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.1.6 等待
int sem_wait(sem_t *sem)
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.1.7 尝试等待
int sem_trywait(sem_t *sem)
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.1.8 获取信号量的值
int sem_getvalue(sem_t *sem, int *sval)
No. |
参数 |
含义 |
1 |
sem |
信号量的指针 |
2 |
sval |
信号量的值 |
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
数据竞争解决方法
上面竞争可以使用信号量解决。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
int main(int argc,char * argv[]){
sem_t* sem = sem_open("/sem.tmp",O_CREAT|O_RDWR,0644,1);
fork();
int i=0;
for(;i<5;i++){
sleep(1);
sem_wait(sem);
printf("PID:%d,enter\n",getpid());
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
sem_post(sem);
}
}
1.2.2 匿名信号量/基于内存
No. |
操作 |
函数 |
1 |
初始化 |
int sem_init (sem_t *sem , int pshared, unsigned int value) |
2 |
销毁 |
int sem_destroy(sem_t *sem) |
3 |
挂出 |
int sem_post(sem_t *sem) |
4 |
等待 |
int sem_wait(sem_t *sem) |
5 |
尝试等待 |
int sem_trywait(sem_t *sem) |
6 |
获取信号量的值 |
int sem_getvalue(sem_t *sem, int *sval) |
其中3~4操作与命名信号量相同。
1.2.2.1 初始化
int sem_init (sem_t *sem , int pshared, unsigned int value)
No. |
参数 |
含义 |
1 |
sem |
信号量的指针 |
2 |
pshared |
共享方式。0 :线程间共享;1 :进程间共享,需要共享内存 |
3 |
value |
信号量初始值 |
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
1.2.2.2 销毁
int sem_destroy(sem_t *sem)
No. |
返回值 |
含义 |
1 |
-1 |
出错 |
2 |
0 |
成功 |
数据竞争解决方法
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
int main(int argc,char * argv[]){
sem_t* sem = sem_open("/sem.tmp",O_CREAT|O_RDWR,0644,0);
fork();
int i=0;
for(;i<5;i++){
sleep(1);
sem_wait(sem);
printf("PID:%d,enter\n",getpid());
printf("PID:%d,do something\n",getpid());
printf("PID:%d,leave\n",getpid());
sem_post(sem);
}
}
小结

命名信号量与匿名信号量
案例
模拟一个停车场的电子显示牌
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <semaphore.h>
int main(int argc,char * argv[]){
sem_t* sem = sem_open(argv[1],O_CREAT,0644,atoi(argv[2]));
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <semaphore.h>
void handler(int sig){
printf("PID:%d,prepare to leave\n",getpid());
}
int main(int argc,char * argv[]){
signal(SIGINT,handler);
sem_t* sem = sem_open(argv[1],O_RDWR);
sem_wait(sem);
int val;
sem_getvalue(sem,&val);
printf("PID:%d,enter. park %d\n",getpid(),val);
printf("PID:%d,do something\n",getpid());
pause();
sem_post(sem);
sem_getvalue(sem,&val);
printf("PID:%d,leave. park %d\n",getpid(),val);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <semaphore.h>
void handler(int sig){
printf("PID:%d,prepare to leave\n",getpid());
}
int main(int argc,char * argv[]){
signal(SIGINT,handler);
sem_t* sem = sem_open(argv[1],O_RDWR);
if(-1 == sem_trywait(sem)){
perror("no park");
return 1;
}
int val;
sem_getvalue(sem,&val);
printf("PID:%d,enter. park %d\n",getpid(),val);
printf("PID:%d,do something\n",getpid());
pause();
sem_post(sem);
sem_getvalue(sem,&val);
printf("PID:%d,leave. park %d\n",getpid(),val);
}
问题
命名信号量与匿名信号量能否用于非亲缘线程?
练习
把信号量封装成一个信号量类
网友评论