代码之家  ›  专栏  ›  技术社区  ›  Sasha

信号系统调用是否可以与C++类的静态成员一起使用?

  •  2
  • Sasha  · 技术社区  · 15 年前

    在*nix平台上是否支持以下功能?

        #include <cstdio>
        #include <sys/types.h>
        #include <signal.h>
        #include <unistd.h>
    
        class SignalProcessor
        {
         public:
          static void OnMySignal(int sig_num)
          {
              printf("Caught %d signal\n", sig_num);
              fflush(stdout);
    
              return;
          } 
        }; 
        using namespace std;
    
       int main()
       {
    
              signal(SIGINT,SingalProcessor::OnMySignal);
              printf("Ouch\n");
    
              pause();
    
              return 0;
       }
    
    3 回复  |  直到 15 年前
        1
  •  5
  •   Loki Astari    15 年前

    技术上不,你不能。

    碰巧,您的编译器使用的调用约定与“c”函数使用的调用约定相同。由于C++的ABI未被定义,编译器的下一版本可以自由使用完全不同的调用约定,这将使代码混乱,没有编译器的警告。

    见: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
    参见本节末尾的注释

    注意:静态成员函数不需要调用实际对象, 所以指向静态成员函数的指针通常与正则函数类型兼容 指向函数的指针。然而,尽管它可能适用于大多数编译器, 它实际上必须是一个外部的“c”非成员函数才能正确, 因为“C链接”不仅包括名称管理之类的内容,而且还包括 调用约定,可能在C和C++之间有所不同。

    编辑:
    回答萨沙的评论:

    以线程为例:

    #include <iostream>
    class Thread
    {    public:   virtual void run()  = 0; };
    
    extern "C" void* startThrerad(void* data)
    {
        Thread*  thread = reinterpret_cast<Thread*>(data);
        try
        {
            thread->run();
        }
        catch(...)
        {    /* Log if required. Don't let thread exit with exception. */ }
        return NULL;
    }
    class MyJob: public Thread
    {
        public: virtual void run() {std::cout << "HI\n";}
    };
    int main()
    {
        MyJob     job; // MyJob inherits from Thread
        pthread_t th;
    
        // In most situation you do not need to dynamic cast.
        // But if you use multiple inheritance then things may get
        // interesting, as such best to always use it.
        pthread_create(&th,NULL,startThrerad,dynamic_cast<Thread*>(&job));
    
        void*     result;
        pthread_join(th,&result);
    }
    
        2
  •  -1
  •   Mark Jones    15 年前

    那就行了。实际上,您可以扩展该函数来调用依赖于捕获的信号的类的特定实例。例如,如果向类中添加一个非静态方法进程,则可以这样做:

    SignalProcessor* sp[MAX_SIGNALS];
    
    static void SignalProcessor::OnMySignal(int sig_num)
    {
          printf("Caught %d signal\n", sig_num);
    
          if (0 < sp[sig_num])
                sp[sig_num]->Process();
    
          fflush(stdout);
    
          return;
    
    }
    
        3
  •  -1
  •   T.E.D.    15 年前

    我在windows thead程序和其他各种回调中做了同样的工作,并且RTX总是中断。唯一真正的gotcha是成员必须是静态的(您已经知道了),并且您必须确保您的例程设置为使用标准的C/System调用约定。遗憾的是,您如何做到这一点取决于平台。在Win32中,它带有“uu stdcall”修饰符。

    请注意,可以使用指针参数中的passback将此类调用“转换”为普通类方法调用。就像这样(“self_calling_callback”是静态方法):

    unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
       if (parameter) {
          basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
          thread->action_callback();
       }
       return 0; 
       // The value returned only matters if someone starts calling GetExitCodeThread
       // to retrieve it.
    }
    
    basic_thread::basic_thread () {
       // Start thread.
       m_Handle = CreateThread(NULL,
                               0,
                               self_calling_callback,
                               (PVOID)this,
                               0,
                               &m_ThreadId );
       if( !IsHandleValid() )
          throw StartException("CreateThread() failed", GetLastError());
    }