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

本文探讨了sem_unlink函数的行为特点,即它会立即删除信号量名称,但信号量本身需等所有进程关闭后才销毁。通过示例代码展示了信号量在调用sem_unlink后的状态变化及对后续创建同名信号量的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

sem_unlink() removes the named semaphore referred to by name.  
The semaphore name
is removed immediately. The semaphore is
destroyed 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这时个可以看到输出为:

复制代码
xzc@xzc-HP-ProBook-4446s:~/code/sem$ ./sem_create
sleep now ....value is 1
xzc@xzc-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

复制代码
xzc@xzc-HP-ProBook-4446s:~/code/sem$ ./sem_create
sleep now ....value is 1

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

xzc@xzc-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这是要闹哪样。

转自:http://www.cnblogs.com/coding-my-life/p/4215862.html?utm_source=tuicool

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值