Linux:signal调用类成员函数

Unix:signal调用类成员函数

  (2013-05-19 18:29:51)
标签: 

杂谈

分类: Unix_Programming
       这个问题早在使用signal时就碰到过,好不容易找到signal使用static型类成员函数的方法,但是发现不能传递参数,终究还是不行,直到在《APUE》上看到pthread和signal这一节,找到sigwait这个工具,这个问题总算是得到解决。
****************************************************************************************************
       为了叙述的方便,使用一个实际的例子,目的很简单,期望能够完成类似signal(signo , 类成员函数)这样的功能。 先说说为什么不能直接使用signal(signo , 类成员函数)这种形式,signal函数的原型如下:
--------------------------------------------------------------
void (*signal(int signo , void (*func)(int)))(int);
signo:表示需要处理的信号;
func:是一个指向void funciont(int)类型的函数指针;
返回值:返回值是一个指向void function(int)类型的函数指针。
--------------------------------------------------------------
    这是因为普通的C++成员函数都隐含了一个传递函数作为参数,亦即“this”指针,C++通过传递this指针给其成员函数从而实现程序函数可以访问类型成员。 这也可以理解为什么C++类的多个实例可以共享成员函数却有不同的数据成员。由于this指针的作用,使得将一个类型的成员函数作为signal函数参数时就会因为隐含的this指针使得函数参数不匹配,从而导致signal函数失败。
(摘自:http://www.cnblogs.com/this-543273659/archive/2011/08/17/2143576.html)

       上面的这个问题和类成员函数作为线程函数一样,下面这篇文章中说过解决的办法:
http://blog.sina.com.cn/s/blog_ac9fdc0b0101mhxp.html
       使用static虽然貌似可以,但pthread_create和signal有一个本质的区别。pthread_create可以传入参数,这样可以将this作为参数传递给线程函数,然后利用this来调用类型成员函数,但是singal的信号处 理函数只能是void function(int)形式,不能想办法将this传递进去。这是最主要的问题,而且在我看来貌似是无解,即使是使用signal 的高端搞法sigaction也不行。因为signal是由内核发出的,它真心不知道这么多东西(这句话瞎说的 Unix:signal调用类成员函数 Unix:signal调用类成员函数),所以这条路走不通。下面是一种曲线救国的方法,可以实现完全相同的功能。
****************************************************************************************************
流程如下
(1)使用sigaddset创建信号屏蔽集(需要处理的信号)
(2)使用pthread_sigmask阻止信号发送给当前进程中所有线程;
(3)创建处理信号的线程函数signalThreadFunction(static类型)。需要传递this参数,可以参考:http://blog.sina.com.cn/s/blog_ac9fdc0b0101mhxp.html
(4)在线程函数中还原this,利用this调用实际处理信号的类成员函数this->signalFunction;
(5)在处理信号的类成员函数signalFunction中使用sigwait来等待信号的发生,然后可以随意的处理了。

-----------------------------------------------------------------------------------
codes speak much more than words:
  14 //===========================================
  15
  16 void error(const char *message)
  17 {
  18     perror(message);
  19     exit(-1);
  20 }
  21
  22 //==========================================
 23 //main function wait the Ctrl+\ to quit
 24 //wait for Ctrl+c to show interrupt

  25 class SignalKiller
  26 {
  27 public:
  28     SignalKiller()
  29         :quitFlag_(0)
  30     {
  31         if(pthread_mutex_init(&lock_ , NULL) != 0)
  32             error("error in pthread_mutex_init");
  33         if(pthread_cond_init(&wait_ , NULL) != 0)
  34             error("error in pthread_cond_int");
  35     }
  36     ~SignalKiller()
  37     {
  38         if(pthread_mutex_destroy(&lock_) != 0)
  39             error("error in pthread_mutex_init");
  40         if(pthread_cond_destroy(&wait_) != 0)
  41             error("error in pthread_cond_int");
  42     }
  43
  44     void run();
  45 private:
  46   static void *signalThreadFunction(void *arg);
 47   void signalFunction();

  48 private:
  49     int quitFlag_;
  50     sigset_t mask_;
  51     pthread_mutex_t lock_;
  52     pthread_cond_t wait_;
  53 };
  54
  55 //===========================================
  56 void   SignalKiller::run()
  57 {
  58     sigset_t oldMask;
  59     pthread_t thread;
  60
 61   sigemptyset(&mask_);
 62   sigaddset(&mask_ , SIGINT);
 63   sigaddset(&mask_ , SIGQUIT);
 64
 65   if(pthread_sigmask(SIG_BLOCK, &mask_ , &oldMask) != 0)
 66     error("error in pthread_sigmask");

  67
 68   if(pthread_create(&thread,NULL,signalThreadFunction,(void*)this) != 0)
 69     error("error in pthread_create");

  70
  71     ///wait for quitFlag to be 1
  72     pthread_mutex_lock(&lock_);
  73     while(quitFlag_ == 0)
  74         pthread_cond_wait(&wait_ , &lock_);
  75     pthread_mutex_unlock(&lock_);
  76
  77     //reset the signal mask to be old mask
  78     if(sigprocmask(SIG_SETMASK , &oldMask , NULL) < 0)
  79         error("error in sigprocmask");
  80 }
  81
  82 //===============================================
  83 void *SignalKiller::signalThreadFunction(void *arg)
 84 {
 85   SignalKiller *thisOne = (SignalKiller*)arg;
 86   //using the member function to process signal
 87   thisOne->signalFunction();
 88   return NULL;
 89
 }

  90
  91 //===============================================
  92 void SignalKiller::signalFunction()
  93 {
  94     int signo;
  95
  96     while(1)
  97     {
  98         if(sigwait(&mask_ , &signo) != 0)
  99             error("error in sigwait");
100
101         switch(signo)
102         {
103             case SIGINT:
104                 printf("\ninterrupt\n");
105                 break;
106             case SIGQUIT:
107             {
108                 printf("\nquit\n");
109                 pthread_mutex_lock(&lock_);
110                 quitFlag_ = 1;
111                 pthread_mutex_unlock(&lock_);
112                 pthread_cond_signal(&wait_);
113                 exit(0);
114             }
115             default:
116                 printf("unexcepted signal %d\n" , signo);
117                 exit(1);
118         }
119     }
120 }
121
122 //================================================
123 int main()
124 {
125     SignalKiller chenHuan;
126     chenHuan.run();
127
128     return 0;
129 }
结果突出一个洋气:
[chenhuan:~/Dropbox/programming_unix/lesson12]$./chen
^C
interrupt
^C
interrupt
^C
interrupt
^C
interrupt
^\
quit
[chenhuan:~/Dropbox/programming_unix/lesson12]$
****************************************************************************************************
       每次说举个简单的例子,写着写着就上百行了。想当年考计算机二级,50行代码就顶天了,上机考试碰到链表几乎就是一个字“死”,哈哈,那时真是挺欢乐的~~~~ Unix:signal调用类成员函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值