赞
踩
概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的
PV操作概念:
生产者和消费者场景
- P(S) 含义如下:
-
- if (信号量的值大于0) {
-
- 申请资源的任务继续运行;
-
- 信号量的值减一;
-
- } else {
-
- 申请资源的任务阻塞;
-
- }
-
- V(S) 含义如下:
-
- 信号量的值加一;
-
- if (有任务在等待资源) {
-
- 唤醒等待的任务,让其继续运行
-
- }
信号灯P操作
- int sem_wait(sem_t *sem);
-
- 获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取
信号灯V操作
- int sem_post(sem_t *sem);
-
- 释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem上的线程从sem_wait函数中返回
注意:编译posix信号灯需要加pthread动态库。
三种信号灯:
Posix 有名信号灯
Posix 无名信号灯 (linux只支持线程同步)
System V 信号灯
Posix 有名信号灯和无名信号灯使用:
有名信号灯打开:
- sem_t *sem_open(const char *name, int oflag);
- sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);
- 参数:
- name:name是给信号灯起的名字
- oflag:打开方式,常用O_CREAT
- mode:文件权限。常用0666
- value:信号量值。二元信号灯值为1,普通表示资源数目
信号灯文件位置:/dev/shm
有名信号灯关闭
int sem_close(sem_t *sem);
有名信号灯的删除
int sem_unlink(const char* name);
有名信号灯:
sem_w.c
- #include<stdio.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #include<semaphore.h>
- #include<string.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<sys/ipc.h>
- #include<sys/shm.h>
-
-
- int main()
- {
- key_t key;
- key = ftok(".",100);
- if(key < 0)
- {
- perror("ftok");
- return 0;
- }
- int shmid;
- shmid = shmget(key,500,0666|IPC_CREAT);
- if(shmid < 0)
- {
- perror("shmget");
- return 0;
- }
-
- char* shmaddr;
- shmaddr = shmat(shmid,NULL,0);
-
- sem_t* sem_r,*sem_w;
- sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
- sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
-
- while(1)
- {
- sem_wait(sem_w);
- printf(">");
- fgets(shmaddr,500,stdin);
- sem_post(sem_r);
- }
-
- return 0;
- }
sem_r.c
- #include<stdio.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #include<semaphore.h>
- #include<string.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<sys/ipc.h>
- #include<sys/shm.h>
-
-
- int main()
- {
- key_t key;
- key = ftok(".",100);
- if(key < 0)
- {
- perror("ftok");
- return 0;
- }
- int shmid;
- shmid = shmget(key,500,0666|IPC_CREAT);
- if(shmid < 0)
- {
- perror("shmget");
- return 0;
- }
-
- char* shmaddr;
- shmaddr = shmat(shmid,NULL,0);
-
- sem_t* sem_r,*sem_w;
- sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
- sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
-
- while(1)
- {
- sem_wait(sem_r);
- printf("%s\n",shmaddr);
- sem_post(sem_w);
- }
-
- return 0;
- }
运行结果:
test_r.c
- #include<stdio.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #include<semaphore.h>
- #include<string.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<sys/ipc.h>
- #include<sys/shm.h>
- #include<signal.h>
-
- void handle(int sig)
- {
- sem_unlink("mysem_w");
- exit(0);
- }
-
-
- int main()
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
-
- key_t key;
- key = ftok(".",100);
- if(key < 0)
- {
- perror("ftok");
- return 0;
- }
- int shmid;
- shmid = shmget(key,500,0666|IPC_CREAT);
- if(shmid < 0)
- {
- perror("shmget");
- return 0;
- }
-
- char* shmaddr;
- shmaddr = shmat(shmid,NULL,0);
-
- sem_t* sem_r,*sem_w;
- sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
- sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
-
- while(1)
- {
- sem_wait(sem_r);
- printf("%s\n",shmaddr);
- sem_post(sem_w);
- }
-
- return 0;
- }
test_w.c
- #include<stdio.h>
- #include<fcntl.h>
- #include<sys/stat.h>
- #include<semaphore.h>
- #include<string.h>
- #include<unistd.h>
- #include<stdlib.h>
- #include<sys/ipc.h>
- #include<sys/shm.h>
- #include<signal.h>
-
- void handle(int sig)
- {
- sem_unlink("mysem_r");
- exit(0);
- }
-
- int main()
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
-
- key_t key;
- key = ftok(".",100);
- if(key < 0)
- {
- perror("ftok");
- return 0;
- }
- int shmid;
- shmid = shmget(key,500,0666|IPC_CREAT);
- if(shmid < 0)
- {
- perror("shmget");
- return 0;
- }
-
- char* shmaddr;
- shmaddr = shmat(shmid,NULL,0);
-
- sem_t* sem_r,*sem_w;
- sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
- sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
-
- while(1)
- {
- sem_wait(sem_w);
- printf(">");
- fgets(shmaddr,500,stdin);
- sem_post(sem_r);
- }
-
- return 0;
- }
运行结果:
无名信号灯初始化
- int sem_init(sem_t *sem, int shared, unsigned int value);
- 参数:
- sem:需要初始化的信号灯变量
- shared: shared指定为0,表示信号量只能由初始化这个信号量的进程使用,不能在进程间使用,linux 不支持进程间同步。
- Value:信号量的值
无名信号灯销毁
int sem_destroy(sem_t* sem);
无名信号灯:
该程序包含一个主进程和一个读取进程。主进程负责从标准输入中读取用户输入,并将其写入共享内存中,读取进程则从共享内存中读取数据并输出到标准输出。
1.信号处理函数,用于在程序中断时销毁信号量destroysem
2.读取进程函数readmem
- sem_wait(&sem_r); // 等待写入信号量
-
- printf("%s\n",shmaddr); // 读取共享内存内容并打印
-
- sem_post(&sem_w); // 发送写入信号量
3.设置信号处理函数sigaction
4.生成共享内存ftok
5.创建共享内存shmget
6.将共享内存连接到当前进程的地址空间shmat
7.初始化信号量sem_init
8.创建读取进程pthread_create
9.读取数据并输出到标准输出
- sem_wait(&sem_w); // 等待读取信号量
- printf(">");
- fgets(shmaddr,500,stdin); // 从标准输入读取数据到共享内存
- sem_post(&sem_r); // 发送读取信号量
具体代码:
- #include <fcntl.h> /* For O_* constants */
- #include <sys/stat.h> /* For mode constants */
- #include <semaphore.h>
-
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <signal.h>
- #include <pthread.h>
-
-
- sem_t sem_r,sem_w;
- char *shmaddr;
- void destroysem(int sig){
-
- sem_destroy(&sem_r);
- sem_destroy(&sem_w);
- exit(0);
-
- }
-
- void *readmem(void *arg){
- while(1){
- sem_wait(&sem_r);
- printf("%s\n",shmaddr);
- sem_post(&sem_w);
-
- }
-
- }
-
-
- int main(){
-
-
- key_t key;
- int shmid;
-
- struct sigaction act;
- act.sa_handler = destroysem;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
-
- sigaction(SIGINT,&act,NULL);
-
- key = ftok(".",100);
- if(key<0){
- perror("ftok");
- return 0;
- }
-
- shmid = shmget(key,500,0666|IPC_CREAT);
- if(shmid<0){
- perror("shmget");
- return 0;
- }
-
- shmaddr = shmat(shmid,NULL,0);
-
-
- sem_init(&sem_r,0,0);
- sem_init(&sem_w,0,1);
-
- pthread_t tid;
- pthread_create(&tid,NULL,readmem,NULL);
-
- while(1){
- sem_wait(&sem_w);
- printf(">");
- fgets(shmaddr,500,stdin);
- sem_post(&sem_r);
- }
-
- }
这个程序的主要功能是从标准输入中读取用户输入,并将其写入共享内存,然后另一个进程从共享内存中读取数据并打印到标准输出。
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。