關於sem_unlink什么時候刪除信號量


  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這是要鬧哪樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM