关于sem_unlink什么时候删除信号量

  sem_unlink在man手册里有这么一段话:

sem_unlink() removes the named semaphore referred to by name.  The semaphore name is removed immediately.  The semaphore  isdestroyed  once all other processes that have the semaphore open close it.

这段话的意思是说,sem_unlink会马上删除指定的信号量名,但要等到所有打开该信号量的进程关闭该信号量后才删除该信号。详细地说,当进程创建一个有名信号量,会在/dev/shm下生成一个sem.xxx的文件,所有打开该信号量的进程(包括创建它的进程)都会增加该文件的引用计数,并且这个计数由内核管理。当调用sem_unlink时,/dev/shm下的sem.xxx文件会马上被删除,但是信号量本身并没有被删除,所有已打开该信号量的进程仍能正常使用它。直到所有打开该信号量的进程关闭该信号量后,内核才真正删除信号量。

  因此,信号量跟sem.xxx并不是共存亡的。下面来测试下:

/* sem_create.cpp */
#include <iostream>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>

int main()
{
    sem_t *psem = sem_open( "/sem_test",O_CREAT,S_IRWXU,1 );
    if ( SEM_FAILED == psem )
    {
        std::cout << "sem_open fail:" << strerror(errno) << std::endl;
        return 0;
    }

    int sval = 0;
    sem_getvalue( psem,&sval );

    std::cout << "sleep now ....value is " << sval << std::endl;
    sleep( 30 );

    sem_getvalue( psem,&sval );
    std::cout << "wake up ....value is " << sval << std::endl;

    sem_post( psem );
    sem_getvalue( psem,&sval );
    std::cout << "raise value and try again ....value is " << sval << std::endl;

    sem_close( psem );
}
/**
 *
 * sem_destruct.cpp
 */

#include <iostream>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <cerrno>
#include <cstring>

int main()
{
    sem_t *psem = sem_open( "/sem_test",O_CREAT,S_IRWXU,1 );
    if ( SEM_FAILED == psem )
    {
        std::cout << "sem_open fail:" << strerror(errno) << std::endl;
        return 0;
    }

    std::cout << "decrease value and remove sem now..." << std::endl;
    sem_wait ( psem );

    sem_close( psem );
    sem_unlink( "/sem_test" );

    std::cout << "sem should remove from /dev/shm,but not really remove" << std::endl;
}

分别编译上面的文件:

g++ -pthread -o sem_create sem_create.cpp
g++ -pthread -o sem_destruct sem_destruct.cpp

先运行sem_create,再运行sem_destruct这时个可以看到输出为:

[email protected]:~/code/sem$ ./sem_create
sleep now ....value is 1
[email protected]-HP-ProBook-4446s:~/code/sem$ ./sem_destruct
decrease value and remove sem now...
sem should remove from /dev/shm,but not really remove
wake up ....value is 0
raise value and try again ....value is 1

可以看到,即使sem_destruct从/dev/shm把信号量删除了,ls /dev/shm也确认对应的文件删除了。但是经过sleep的sem_create进程在wake up后仍能对信号量进行操作。

  可以看到,有名信号量一旦打开后,跟名字并没有多大关系。下面再来测试有名信号量调用sem_unlink但仍有进程在使用,这时另外一个进程又要创建同名信号量的情况

/**
  *
  * sem_again.cpp
  */

#include <iostream>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>

int main()
{
    sem_t *psem = sem_open( "/sem_test",O_CREAT|O_EXCL,S_IRWXU,1 );
    if ( SEM_FAILED == psem )
    {
        std::cout << "sem_open fail:" << strerror(errno) << std::endl;
        return 0;
    }

    int sval = 0;
    sem_getvalue( psem,&sval );

    //std::cout << "sleep now ....value is " << sval << std::endl;
    //sleep( 30 );

    sem_getvalue( psem,&sval );
    std::cout << "value is " << sval << std::endl;

    sem_post( psem );
    sem_getvalue( psem,&sval );
    std::cout << "raise value and try again ....value is " << sval << std::endl;

    sem_close( psem );
    sem_unlink( "/sem_test" );
}

编译一下:g++ -pthread -o sem_again sem_again.cpp,然后依次运行sem_create、sem_destruct、sem_again

[email protected]:~/code/sem$ ./sem_create
sleep now ....value is 1

[email protected]-HP-ProBook-4446s:~/code/sem$ ./sem_destruct
decrease value and remove sem now...
sem should remove from /dev/shm,but not really remove

[email protected]-HP-ProBook-4446s:~/code/sem$ ./sem_again
value is 1
raise value and try again ....value is 2

wake up ....value is 0
raise value and try again ....value is 1

在sem_again中特意使用了O_CREATE|O_EXCL标志,如果已存在同名信号量,则创建失败。但从上面的结果来看,创建成功并且互不干扰。也就是说,一个有名信号量,在打开并调用sem_unlink后可以当作无名信号量来使用(但这时新的进程还想使用该信号量,不可能了)。

  注:上面只做了简单测试,并未测试sem_unlink后各进程的竞争情况,在生产环境请自行测试。

PS:在debian 6上,不用unistd.h也能调用sleep函数,在ubuntu 14.04上不行。在debian 6上是链接的库是-lrt,在ubuntu 14.04上是-pthread,-lrt不行。linux这是要闹哪样。

时间: 2024-10-08 03:11:28

关于sem_unlink什么时候删除信号量的相关文章

信号量、互斥锁,读写锁和条件变量的区别

信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都 在sem_wait的时候,就阻塞在那里).当信号量为单值信号量是,也可以完成一个资源的互斥访问.有名信号量:可以用于不同进程间或多线程间的互斥与同步 创建打开有名信号量 sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag

Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post 有名信号量 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <semaphore.h> sem_t *sem_open(co

【转载】Linux的进程间通信-信号量

原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问问题和甄误反馈,共同进步. 微博ID:orroz 微信公众号:Linux系统技术 前言 信号量又叫信号灯,也有人把它叫做信号集,本文遵循<UNIX环境高级编程>的叫法,仍称其为信号量.它的英文是semaphores,本意是“旗语”“信号”的意思.由于其叫法中包含“信号”这个关键字,所以容易跟另一个

IPC之Posix信号量详解

基本概念: 信号量(semaphore)是一种用于提供不同进程间或一个给定进程的不用线程间同步手段的原语. 共有三种类型的信号量: 1)Posix有名信号量:使用Posix IPC名字标识,可用于进程或线程间的同步. 2)Posix基于内存的信号量:存放在共享内存区中,可用于进程或线程间的同步. 3)System V信号量:在内核中维护,可用于进程或者线程间同步.(本文不讨论System V信号量) 一个进程可以在某个信号量上执行三种操作: (1)创建(create)一个信号量.这还要求调用者指

POSIX信号量

DESCRIPTION POSIX 信号量允许进程间和线程间同步他们的操作. 一个信号量是一个整型(integer),其值不能小于0. 信号量允许2中操作:给信号量的值加1(sem_post); 给信号量的值减一(sem_wait). 如果信号量的值为0, 那么sem_wait() 函数将会阻塞, 直到信号量的值大于0才会解除阻塞. POSIX 信号量有两种形式: 有名信号量 和 无名信号量. Named semaphores 一个有名信号量有一个唯一的名字, 名字的格式是 /somename;

Linux系统编程——进程同步与互斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥.它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件.前面我们学习了无名信号量的使用(详情请看<无名信号量>),这里我们学习有名信号量的使用. 1)创建一个有名信号量 所需头文件: #include <fcntl.h> #include <sys/stat.h> #include

进程同步与互斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥.它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件.前面我们学习了无名信号量的使用(详情请看<无名信号量>),这里我们学习有名信号量的使用. 1)创建一个有名信号量 所需头文件: #include <fcntl.h> #include <sys/stat.h> #include

进程同步与相互排斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量. 无名信号量一般用于线程间同步或相互排斥,而有名信号量一般用于进程间同步或相互排斥. 它们的差别和管道及命名管道的差别类似.无名信号量则直接保存在内存中,而有名信号量要求创建一个文件.前面我们学习了无名信号量的使用(详情请看<无名信号量>).这里我们学习有名信号量的使用. 1)创建一个有名信号量 所需头文件: #include <fcntl.h> #include <sys/stat.h> #in

linux进程间通信之Posix 信号量用法详解代码举例

Posix信号量不同于System V信号量的信号量集,Posix信号量是单一的信号量,分为有名信号量和无名信号量.Posix有名信号量是使用Posix IPC名字标示的信号量,可用于进程和线程间的同步:Posix无名信号量是指基于内存的信号量,存放在共享内存区中,用于进程与线程间的同步. Posix有名信号量可以是内核维护,也可以在文件系统中维护,这取决于信号量对应的路径名是否映射到了真正的磁盘文件上,如果有映射到则在文件系统中维护,否则在内核中维护,Posix有名信号量由函数sem_open