linux编程时的信号量问题。 我以前用过的信号量头文件是<semaphore.h>,而现在又发现还有个<sys/sem.h>

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux编程时的信号量问题。 我以前用过的信号量头文件是<semaphore.h>,而现在又发现还有个<sys/sem.h>相关的知识,希望对你有一定的参考价值。

请问谁知道他们有什么区别啊。个人感觉还是semaphore,h比较好用,初始化什么的比较方便。

信号量在进程是以有名信号量进行通信的,在线程是以无名信号进行通信的,因为线程linux还没有实现进程间的通信,所以在sem_init的第二个参数要为0,而且在多线程间的同步是可以通过有名信号量也可通过无名信号,但是一般情况线程的同步是无名信号量,无名信号量使用简单,而且sem_t存储在进程空间中,有名信号量必须LINUX内核管理,由内核结构struct ipc_ids 存储,是随内核持续的,系统关闭,信号量则删除,当然也可以显示删除,通过系统调用删除,
消息队列,信号量,内存共享,这几个都是一样的原理。,只不过信号量分为有名与无名

无名使用 <semaphore.h>,
有名信号量<sys/sem.h>
无名信号量不能用进程间通信,
//无名与有名的区别,有名需要KEY值与IPC标识
所以sem_init的第二个参数必须为0,,,,
参考技术A semaphore.h 提供的是 POSIX 标准定义的 semaphore 接口 ( sem_open, sem_wait, ...) ,这组接口使用更简单,设计的较好。

而 sys/sem.h 里 提供的是符合 System V 标准的 semaphore接口 (semget, semop, ...),这些接口都比较老了, linux提供主要是为了兼容老代码。

对于 linux 开发来说,新写的代码,都应该考虑采用 POSIX 标准的信号量。追问

高手啊,目前在看UNIX环境高级编程,虽然这本书被称为圣经,但感觉翻译的不是很好。感觉不太容易理解,呵呵。多谢你的回答,学习了。

追答

可以考虑看原版,很多书翻译的都差,为了挣钱,很多都是不懂的人或者没什么经验的翻译的

追问

能留个您的QQ吗?或者你加我吧,285226942,希望以后有机会多向您请教哦。

linux c编程:信号 sigsuspend

更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞。使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,则又将如何呢?假定信号时SIGINT,实现这一点的一种不正确的方法是:

sigset_t    newmask, oldmask;

 

sigemptyset(&newmask);

sigaddset(&newmask, SIGINT);

/* block SIGINT and save current signal mask */if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

    err_sys("SIG_BLOCK error");

/* critical region of code */if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

    err_sys("SIG_SETMASK error");

/* window is open */

pause();    /* wait for signal to occur */

/* continue processing */

如果在信号阻塞时将其发送给进程,那么该信号的传递就被推迟直到对它解除了阻塞。对应用程序而言,该信号好像发生在解除对SIGINT的阻塞和pause之间。如果发生了这种情况,或者如果在解除阻塞时刻和pause之间确实发生了信号,那么就产生了问题。因为我们可能不会再见到该信号,所以从这种意义上而言,在此时间窗口(解除阻塞和pause之间)中发生的信号丢失了,这样就使pause永远阻塞。

为了纠正此问题,需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。这种功能是由sigsuspend函数提供的。

#include <signal.h>

int sigsuspend( const sigset_t *sigmask );

返回值:-1,并将errno设置为EINTR

 

将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void handler(int sig)   //信号处理程序

{

   if(sig == SIGINT)

      printf("SIGINT sig");

   else if(sig == SIGQUIT)

      printf("SIGQUIT sig");

   else

      printf("SIGUSR1 sig");

}

 

int main()

{

    sigset_t new,old,wait;   //三个信号集

    struct sigaction act;

    act.sa_handler = handler;

    sigemptyset(&act.sa_mask);

    act.sa_flags = 0;

    sigaction(SIGINT, &act, 0);    //可以捕捉以下三个信号:SIGINT/SIGQUIT/SIGUSR1

    sigaction(SIGQUIT, &act, 0);

    sigaction(SIGUSR1, &act, 0);

   

    sigemptyset(&new);

    sigaddset(&new, SIGINT);  //SIGINT信号加入到new信号集中

    sigemptyset(&wait);

    sigaddset(&wait, SIGUSR1);  //SIGUSR1信号加入wait

    sigprocmask(SIG_BLOCK, &new, &old);       //SIGINT阻塞,保存当前信号集到old

   

    //临界区代码执行    

  

    if(sigsuspend(&wait) != -1)  //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1  号,阻塞掉,程序继续挂起;过来其他信号,例如SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset(&wait, SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会唤醒程序。

        printf("sigsuspend error");

    printf("After sigsuspend");

    sigprocmask(SIG_SETMASK, &old, NULL);

    return 0;

}

sigsuspend的原子操作是:

1)设置新的mask阻塞当前进程(上面是用wait替换new,即阻塞SIGUSR1信号)

2)收到SIGUSR1信号,阻塞,程序继续挂起;收到其他信号,恢复原先的mask(即包含SIGINT信号的)

3)调用该进程设置的信号处理函数(程序中如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的)

4)待信号处理函数返回,sigsuspend返回了。(sigsuspend将捕捉信号和信号处理函数集成到一起了)

 

以上是关于linux编程时的信号量问题。 我以前用过的信号量头文件是<semaphore.h>,而现在又发现还有个<sys/sem.h>的主要内容,如果未能解决你的问题,请参考以下文章

linux c编程:信号 sigsuspend

Python网络编程(进程通信信号线程锁多线程)

Linux 多线程编程(二)2019-08-10

函数响应式编程的“信号”表示是不是正确?

linux系统编程:线程同步-信号量(semaphore)

Linux进程间通信 -- 信号量函数 signal()sigaction()