根据: http://www.haiku-os.org/legacy-docs/benewsletter/Issue1-26.html#Engineering1-26
我在g ++ 4.4.6中实现了以下内容!!
#ifndef BENAPHORE_
#define BENAPHORE_
#include <string>
#include <memory>
#include <utility>
#include <semaphore.h>
#include <pthread.h>
#include <assert.h>
class benaphore
{
private:
char fname[128] ;
sem_t* benaphore_sem ;
int benaphore_atom ;
bool closed ;
public:
benaphore()
{
benaphore_atom = 0 ;
}
~benaphore()
{
if(!closed)
{
sem_close(benaphore_sem) ;
sem_unlink(fname) ;
}
}
void close_benaphore()
{
sem_close(benaphore_sem) ;
sem_unlink(fname) ;
closed = true ;
}
void open_benaphore(char* fname_)
{
closed = false ;
strcpy(fname,fname_) ;
benaphore_sem = sem_open(fname,O_CREAT,0644,0);
if(benaphore_sem == SEM_FAILED)
{
printf("benaphore sem_open error \n") ;
}
}
void acquire_benaphore()
{
int previous_value;
previous_value = __sync_fetch_and_add(&benaphore_atom, 1);
if (previous_value > 0)
sem_wait(benaphore_sem);
}
void release_benaphore()
{
int previous_value;
previous_value = __sync_fetch_and_add(&benaphore_atom, -1);
if (previous_value > 1)
sem_post(benaphore_sem);
}
} ;
#endif
和测试来源:
#include "benaphore.hpp"
benaphore b1 ;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int glbCnt[6]={0,0,0,0,0,0} ;
void gexit(int gub)
{
b1.close_benaphore() ;
for(int idx=0;idx<6;idx++)
printf("(%d)\n",glbCnt[idx]) ;
sleep(1) ;
exit(0) ;
}
void *testx(void *arg)
{
long ilocal = (long)arg ;
for(int idx=0;idx<3000000;idx++)
{
//pthread_mutex_lock(&mutex);
b1.acquire_benaphore() ;
++glbCnt[ilocal] ;
b1.release_benaphore() ;
//pthread_mutex_unlock(&mutex);
}
}
int main()
{
char* fname ;
fname = (char*) malloc(80) ;
strcpy(fname,"test_benaphore1") ;
b1.open_benaphore(fname) ;
signal(SIGINT, gexit);
signal(SIGTERM, gexit);
pthread_t id[6];
int iCPU[6]={0,1,2,3,4,5} ;
pthread_create(&id[0],NULL,testx,(void *)(long)iCPU[0] );
pthread_create(&id[1],NULL,testx,(void *)(long)iCPU[1] );
pthread_create(&id[2],NULL,testx,(void *)(long)iCPU[2] );
pthread_create(&id[3],NULL,testx,(void *)(long)iCPU[3] );
pthread_create(&id[4],NULL,testx,(void *)(long)iCPU[4] );
pthread_create(&id[5],NULL,testx,(void *)(long)iCPU[5] );
int i ;
for(i=0;i<6;++i){
pthread_join(id[i],NULL);
}
b1.close_benaphore() ;
for(int idx=0;idx<6;idx++)
printf("(%d)\n",glbCnt[idx]) ;
}
编译:
g ++ --std = c ++ 0x test_benaphore.cpp -lpthread -o test_benaphore.exe
每次我能得到正确的答案,如果让每个线程完成。但是如果我通过键“control-C”发送一个中断信号,那么执行gexit()函数并且大多数应用程序获得“Segmentation fault(core dumped)”,关于中断应用程序10次,将获得9次核心转储,一次没有打印数量少于3,000,000的核心转储。
我不知道为什么会这样,任何意见,建议都会受到赞赏。
答案 0 :(得分:1)
从异步信号处理程序可以安全地做到这一点,请参阅this page的底部以获取列表。请注意,exit
和printf
不在其上。您可以通过调用_exit
来消除段错误。
更好的设计可能是避免在信号处理程序中进行任何复杂的处理,只需设置一个标志......
namespace
{
volatile sig_atomic_t time_to_quit;
}
void gexit(int gub)
{
time_to_quit = 1;
}
..你的线程不时检查
for(int idx=0; !time_to_quit && idx<3000000;idx++)
现在main
执行所有危险的清理工作,与成功路径相同。
答案 1 :(得分:0)
你的close_benaphore
函数不是线程安全的,但你让任何捕获control-C的线程调用它。也许你想在所有线程中阻止SIGINT,但第一个呢?