当前位置:   article > 正文

Linux信号灯

Linux信号灯

概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的

PV操作概念:

生产者和消费者场景

  1. P(S) 含义如下:
  2.      if  (信号量的值大于0) { 
  3.  申请资源的任务继续运行;
  4.             信号量的值减一;
  5. } else {  
  6. 申请资源的任务阻塞;
  7. }
  8. V(S) 含义如下:
  9.      信号量的值加一;
  10.      if (有任务在等待资源) {  
  11. 唤醒等待的任务,让其继续运行
  12. }

信号灯P操作

  1. int sem_wait(sem_t *sem);
  2. 获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取

信号灯V操作

  1. int sem_post(sem_t *sem);
  2. 释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem上的线程从sem_wait函数中返回

注意:编译posix信号灯需要加pthread动态库。

三种信号灯:

Posix 有名信号灯

Posix 无名信号灯 (linux只支持线程同步)

System V 信号灯

Posix 有名信号灯和无名信号灯使用:

 有名信号灯打开:

  1. sem_t *sem_open(const char *name, int oflag);
  2. sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);
  3. 参数:
  4. name:name是给信号灯起的名字
  5. oflag:打开方式,常用O_CREAT
  6. mode:文件权限。常用0666
  7. value:信号量值。二元信号灯值为1,普通表示资源数目

信号灯文件位置:/dev/shm

有名信号灯关闭

int sem_close(sem_t *sem);

有名信号灯的删除

int sem_unlink(const char* name);

 有名信号灯:

 sem_w.c

  1. #include<stdio.h>
  2. #include<fcntl.h>
  3. #include<sys/stat.h>
  4. #include<semaphore.h>
  5. #include<string.h>
  6. #include<unistd.h>
  7. #include<stdlib.h>
  8. #include<sys/ipc.h>
  9. #include<sys/shm.h>
  10. int main()
  11. {
  12. key_t key;
  13. key = ftok(".",100);
  14. if(key < 0)
  15. {
  16. perror("ftok");
  17. return 0;
  18. }
  19. int shmid;
  20. shmid = shmget(key,500,0666|IPC_CREAT);
  21. if(shmid < 0)
  22. {
  23. perror("shmget");
  24. return 0;
  25. }
  26. char* shmaddr;
  27. shmaddr = shmat(shmid,NULL,0);
  28. sem_t* sem_r,*sem_w;
  29. sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
  30. sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
  31. while(1)
  32. {
  33. sem_wait(sem_w);
  34. printf(">");
  35. fgets(shmaddr,500,stdin);
  36. sem_post(sem_r);
  37. }
  38. return 0;
  39. }

sem_r.c

  1. #include<stdio.h>
  2. #include<fcntl.h>
  3. #include<sys/stat.h>
  4. #include<semaphore.h>
  5. #include<string.h>
  6. #include<unistd.h>
  7. #include<stdlib.h>
  8. #include<sys/ipc.h>
  9. #include<sys/shm.h>
  10. int main()
  11. {
  12. key_t key;
  13. key = ftok(".",100);
  14. if(key < 0)
  15. {
  16. perror("ftok");
  17. return 0;
  18. }
  19. int shmid;
  20. shmid = shmget(key,500,0666|IPC_CREAT);
  21. if(shmid < 0)
  22. {
  23. perror("shmget");
  24. return 0;
  25. }
  26. char* shmaddr;
  27. shmaddr = shmat(shmid,NULL,0);
  28. sem_t* sem_r,*sem_w;
  29. sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
  30. sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
  31. while(1)
  32. {
  33. sem_wait(sem_r);
  34. printf("%s\n",shmaddr);
  35. sem_post(sem_w);
  36. }
  37. return 0;
  38. }

运行结果: 

test_r.c

  1. #include<stdio.h>
  2. #include<fcntl.h>
  3. #include<sys/stat.h>
  4. #include<semaphore.h>
  5. #include<string.h>
  6. #include<unistd.h>
  7. #include<stdlib.h>
  8. #include<sys/ipc.h>
  9. #include<sys/shm.h>
  10. #include<signal.h>
  11. void handle(int sig)
  12. {
  13. sem_unlink("mysem_w");
  14. exit(0);
  15. }
  16. int main()
  17. {
  18. struct sigaction act;
  19. act.sa_handler = handle;
  20. act.sa_flags = 0;
  21. sigemptyset(&act.sa_mask);
  22. sigaction(SIGINT,&act,NULL);
  23. key_t key;
  24. key = ftok(".",100);
  25. if(key < 0)
  26. {
  27. perror("ftok");
  28. return 0;
  29. }
  30. int shmid;
  31. shmid = shmget(key,500,0666|IPC_CREAT);
  32. if(shmid < 0)
  33. {
  34. perror("shmget");
  35. return 0;
  36. }
  37. char* shmaddr;
  38. shmaddr = shmat(shmid,NULL,0);
  39. sem_t* sem_r,*sem_w;
  40. sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
  41. sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
  42. while(1)
  43. {
  44. sem_wait(sem_r);
  45. printf("%s\n",shmaddr);
  46. sem_post(sem_w);
  47. }
  48. return 0;
  49. }

 test_w.c

  1. #include<stdio.h>
  2. #include<fcntl.h>
  3. #include<sys/stat.h>
  4. #include<semaphore.h>
  5. #include<string.h>
  6. #include<unistd.h>
  7. #include<stdlib.h>
  8. #include<sys/ipc.h>
  9. #include<sys/shm.h>
  10. #include<signal.h>
  11. void handle(int sig)
  12. {
  13. sem_unlink("mysem_r");
  14. exit(0);
  15. }
  16. int main()
  17. {
  18. struct sigaction act;
  19. act.sa_handler = handle;
  20. act.sa_flags = 0;
  21. sigemptyset(&act.sa_mask);
  22. sigaction(SIGINT,&act,NULL);
  23. key_t key;
  24. key = ftok(".",100);
  25. if(key < 0)
  26. {
  27. perror("ftok");
  28. return 0;
  29. }
  30. int shmid;
  31. shmid = shmget(key,500,0666|IPC_CREAT);
  32. if(shmid < 0)
  33. {
  34. perror("shmget");
  35. return 0;
  36. }
  37. char* shmaddr;
  38. shmaddr = shmat(shmid,NULL,0);
  39. sem_t* sem_r,*sem_w;
  40. sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
  41. sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);
  42. while(1)
  43. {
  44. sem_wait(sem_w);
  45. printf(">");
  46. fgets(shmaddr,500,stdin);
  47. sem_post(sem_r);
  48. }
  49. return 0;
  50. }

运行结果: 

无名信号灯初始化 

  1. int sem_init(sem_t *sem, int shared, unsigned int value);
  2. 参数:
  3. sem:需要初始化的信号灯变量
  4. shared: shared指定为0,表示信号量只能由初始化这个信号量的进程使用,不能在进程间使用,linux 不支持进程间同步。
  5. Value:信号量的值

 无名信号灯销毁

int sem_destroy(sem_t* sem);

无名信号灯: 

        该程序包含一个主进程和一个读取进程。主进程负责从标准输入中读取用户输入,并将其写入共享内存中,读取进程则从共享内存中读取数据并输出到标准输出。

1.信号处理函数,用于在程序中断时销毁信号量destroysem

2.读取进程函数readmem

  1. sem_wait(&sem_r); // 等待写入信号量
  2. printf("%s\n",shmaddr); // 读取共享内存内容并打印
  3. sem_post(&sem_w); // 发送写入信号量

3.设置信号处理函数sigaction

4.生成共享内存ftok

5.创建共享内存shmget

6.将共享内存连接到当前进程的地址空间shmat

7.初始化信号量sem_init

8.创建读取进程pthread_create

9.读取数据并输出到标准输出

  1. sem_wait(&sem_w); // 等待读取信号量
  2. printf(">");
  3. fgets(shmaddr,500,stdin); // 从标准输入读取数据到共享内存
  4. sem_post(&sem_r); // 发送读取信号量

具体代码: 

  1. #include <fcntl.h> /* For O_* constants */
  2. #include <sys/stat.h> /* For mode constants */
  3. #include <semaphore.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #include <sys/ipc.h>
  8. #include <sys/shm.h>
  9. #include <signal.h>
  10. #include <pthread.h>
  11. sem_t sem_r,sem_w;
  12. char *shmaddr;
  13. void destroysem(int sig){
  14. sem_destroy(&sem_r);
  15. sem_destroy(&sem_w);
  16. exit(0);
  17. }
  18. void *readmem(void *arg){
  19. while(1){
  20. sem_wait(&sem_r);
  21. printf("%s\n",shmaddr);
  22. sem_post(&sem_w);
  23. }
  24. }
  25. int main(){
  26. key_t key;
  27. int shmid;
  28. struct sigaction act;
  29. act.sa_handler = destroysem;
  30. act.sa_flags = 0;
  31. sigemptyset(&act.sa_mask);
  32. sigaction(SIGINT,&act,NULL);
  33. key = ftok(".",100);
  34. if(key<0){
  35. perror("ftok");
  36. return 0;
  37. }
  38. shmid = shmget(key,500,0666|IPC_CREAT);
  39. if(shmid<0){
  40. perror("shmget");
  41. return 0;
  42. }
  43. shmaddr = shmat(shmid,NULL,0);
  44. sem_init(&sem_r,0,0);
  45. sem_init(&sem_w,0,1);
  46. pthread_t tid;
  47. pthread_create(&tid,NULL,readmem,NULL);
  48. while(1){
  49. sem_wait(&sem_w);
  50. printf(">");
  51. fgets(shmaddr,500,stdin);
  52. sem_post(&sem_r);
  53. }
  54. }

        这个程序的主要功能是从标准输入中读取用户输入,并将其写入共享内存,然后另一个进程从共享内存中读取数据并打印到标准输出。

运行结果: 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/244973
推荐阅读
相关标签
  

闽ICP备14008679号