找回密码
 立即注册
首页 业界区 安全 POSIX信号量

POSIX信号量

稞冀 2025-6-11 15:52:41
POSIX信号量

信号量的概念

信号量可以用于多个不同进程间或者同一个进程中多个不同线程间进行同步的方案,Linux系统提供了POSIX信号量和IPC对象中的信号量集供用户使用。
POSIX信号量一般用于描述一种共享资源的状态,Linux系统把POSIX信号量分为两种:一种是POSIX匿名信号量,另一种则是POSIX具名信号量,两者区别如下所示:Linux系统中的信号量可以用于进程间通信,也可以用于同一个进程中多个线程的通信,而POSIX匿名信号量则是专门在进程中的多个线程间进行使用的一种信号量,也就是只存在于内存中。POSIX匿名信号量主要是在进程中的多条线程中使用,而POSIX具名信号量则主要是在多个进程中使用,并且可以存储在根文件系统的 /dev/shm 目录下,可以被系统中任意有权限的进程访问
(1)匿名信号量

A. 初始化POSIX匿名信号量
Linux系统中提供了一个名称叫做sem_init()的函数接口,用户利用该接口可以对POSIX匿名信号量进行初始化。。
B. POSIX具名信号量进行P/V操作
对于信号量而言,都是对资源的一种数量的表示,所以进程或者线程在有限的资源进行访问时都需要进行申请和释放,所以Linux系统下提供了两个函数来实现POSIX具名信号量的P/V操作,分别是sem_wait()和sem_post()。
C.练习
练习:设计一个程序,要求在进程中存在两条线程,主线程获取键盘的字符串并输入到数组中,子线程等待主线程输入完成后,在把数组中的字符串输出到终端。要求使用POSIX信号量实现线程的同步。
  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. //全局变量
  5. sem_t sem;
  6. char buf[128]={0};
  7. //子线程
  8. void * task(void *arg)
  9. {
  10.     //设置分离属性
  11.     pthread_detach(pthread_self());
  12.     while(1)
  13.     {
  14.         //对匿名信号量进行P操作
  15.         sem_wait(&sem);//p操作
  16.         
  17.         //打印数组中的字符
  18.         printf("I am pthread,buf=[%s]\n",buf);
  19.         bzero(buf,sizeof(buf));
  20.         //对匿名信号量进行P操作
  21.         sem_post(&sem);//V操作
  22.     }
  23. }
  24. int main()
  25. {
  26.     //1.创建一个线程
  27.     pthread_t thread;
  28.     pthread_create(thread,NULL,task,NULL);
  29.     //2.初始化信号量
  30.     sem_init(&sem,0,1);
  31.     //3.键盘输入
  32.    
  33.     while(1)
  34.     {   
  35.         sem_wait(&sem);//p操作
  36.         scanf("请输入:%s\n",buf);
  37.         sem_post(&sem);//V操作
  38.     }
  39.     sem_close(&sem);
  40.     return 0;
复制代码
(2)有名信号量

POSIX匿名信号量主要是在进程中的多条线程中使用,而POSIX具名信号量则主要是在多个进程中使用,并且可以存储在根文件系统的 /dev/shm 目录下,可以被系统中任意有权限的进程访问。
A. 创建或者打开POSIX具名信号量
由于POSIX具名信号量有自己的文件名称,所以Linux系统提供了一个名称叫做sem_open()的函数接口,用户可以利用该接口创建或者打开POSIX具名信号量。
B. 对POSIX信号量进行P/V
对于信号量而言,都是对资源的一种数量的表示,所以进程或者线程在有限的资源进行访问时都需要进行申请和释放,所以Linux系统下提供了两个函数来实现POSIX匿名信号量的P/V操作,分别是sem_wait()和sem_post()。
注意:如果POSIX具名信号量使用完成后,应该及时关闭,Linux系统提供了名字叫做sem_close()的函数实现该操作
另外,POSIX具名信号量创建完成后是存储在文件系统中的,所以并不会因为进程的结束而被删除,如果用户后期不打算继续使用POSIX具名信号量,linux系统提供了名称叫做sem_unlink()的函数接口实现删除POSIX具名信号量
C.练习
练习:设计两个程序A和B,程序A和程序B需要创建一个共享内存,然后要求程序A把自己的PID写入到共享内存中,当程序A写入完成后,程序B从共享内存中读取程序A的PID并输出到终端,要求双方使用POSIX具名信号量实现同步。
进程A
  1. #include <fcntl.h>           /* For O_* constants */
  2. #include <sys/stat.h>        /* For mode constants */
  3. #include <semaphore.h>
  4. #include <sys/shm.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. int main()
  12. {
  13.     //1.创建共享内存
  14.     int shm_id=shmget(ftok(".",3),4,IPC_CREAT|IPC_EXCL|664);
  15.     if (shm_id == -1)
  16.         {
  17.                 if(errno == EEXIST)
  18.                 {
  19.                         //此时可以再次调用该函数打开共享内存
  20.                         shm_id = shmget(ftok(".",50),4,0644);
  21.                 }
  22.                 else
  23.                 {
  24.                         fprintf(stderr, "shmget error,errno:%d,%s\n",errno,strerror(errno));
  25.                         exit(1);
  26.                 }
  27.         }
  28.     //2.把打开的共享内存段映射到自己的进程空间中
  29.         int * pshm = (int *)shmat(shm_id,NULL,0);
  30.     //3.打开一个POSIX有名信号量,如果不存在则创建
  31.         sem_t * psem = sem_open("named_sem", O_CREAT|O_EXCL,0644,0);
  32.         if(psem == SEM_FAILED)
  33.         {
  34.                 if(errno == EEXIST)
  35.                 {
  36.                         //此时可以再次调用该函数打开共享内存
  37.                         psem = sem_open("named_sem",0);
  38.                 }
  39.                 else
  40.                 {
  41.                         fprintf(stderr, "sem_open error,errno:%d,%s\n",errno,strerror(errno));
  42.                         exit(2);
  43.                 }
  44.         }
  45.         //4.进程A先对临界资源进行访问,然后对POSIX信号量进行V操作
  46.        
  47.         *pshm = getpid();
  48.         sem_post(psem);
  49.        
  50.         return 0;
  51. }
复制代码
进程B
  1. #include <fcntl.h>           /* For O_* constants */
  2. #include <sys/stat.h>        /* For mode constants */
  3. #include <semaphore.h>
  4. #include <sys/shm.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. int main(int argc, char const *argv[])
  12. {
  13.        
  14.         //1.打开一个共享内存,如果不存在则创建
  15.         int shm_id = shmget(ftok(".",50),4,IPC_CREAT|IPC_EXCL|0644);
  16.        
  17.        
  18.         if (shm_id == -1)
  19.         {
  20.                 if(errno == EEXIST)
  21.                 {
  22.                         //此时可以再次调用该函数打开共享内存
  23.                         shm_id = shmget(ftok(".",50),4,0644);
  24.                 }
  25.                 else
  26.                 {
  27.                         fprintf(stderr, "shmget error,errno:%d,%s\n",errno,strerror(errno));
  28.                         exit(1);
  29.                 }
  30.         }
  31.         //2.把打开的共享内存段映射到自己的进程空间中
  32.         int * pshm = (int *)shmat(shm_id,NULL,0);
  33.         //3.打开一个POSIX有名信号量,如果不存在则创建
  34.         sem_t * psem = sem_open("named_sem", O_CREAT|O_EXCL,0644,0);
  35.         if(psem == SEM_FAILED)
  36.         {
  37.                 if(errno == EEXIST)
  38.                 {
  39.                         //此时可以再次调用该函数打开共享内存
  40.                         psem = sem_open("named_sem",0);
  41.                 }
  42.                 else
  43.                 {
  44.                         fprintf(stderr, "sem_open error,errno:%d,%s\n",errno,strerror(errno));
  45.                         exit(2);
  46.                 }
  47.         }
  48.         //4.死循环,防止进程终止
  49.         while(1)
  50.         {
  51.                 //进程B必须等待进程A把PID写入到共享内存中之后才可以输出共享内存段中的数据
  52.                
  53.                 //进程B需要进行P操作
  54.                 sem_wait(psem);
  55.                 //访问临界资源
  56.                 printf("shared memory data is [%d]\n",*pshm);
  57.         }
  58.        
  59.         return 0;
  60. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册