Можно ли использовать системный вызов сигналов со статическими членами класса C ++? - PullRequest
2 голосов
/ 09 июня 2009

Поддерживается ли следующее на * 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 ]

5 голосов
/ 10 июня 2009

Технически нет, вы не можете.

Вам просто повезло, что ваш компилятор использует то же соглашение о вызовах, что и для функций 'C'. Поскольку C ++ ABI не определен, следующая версия компилятора может использовать совершенно другое соглашение о вызовах, и это будет портить ваш код без предупреждения от компилятора.

См .: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
См. Примечание в конце этого раздела

Примечание: статические функции-члены не требуют вызова реального объекта, поэтому указатели на статические функции-члены обычно совместимы по типу с обычными указатели к функции. Однако, хотя это, вероятно, работает на большинстве компиляторов, на самом деле это должна быть внешняя функция "C", не являющаяся членом, чтобы быть правильной, поскольку «C linkage» охватывает не только такие вещи, как искажение имени, но и соглашения о вызовах, которые могут отличаться в C и C ++.

Edit:
Ответить на комментарий Саши:

Использование потоков в качестве примера:

#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);
}
0 голосов
/ 09 июня 2009

Это должно работать просто отлично. Фактически, вы могли бы расширить эту функцию, чтобы вызывать конкретные экземпляры этого класса в зависимости от полученного сигнала. Например, если вы добавите нестатический метод Process в свой класс, вы можете сделать что-то вроде этого:

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;

}
0 голосов
/ 09 июня 2009

Я делаю то же самое с процедурами thead Windows и другими различными обратными вызовами, и RTX все время прерывает. Единственная реальная ошибка состоит в том, что члены должны быть статичными (что вы уже поняли), и что вы должны убедиться, что ваша подпрограмма настроена на использование стандартного соглашения о вызовах системного вызова C /. К сожалению, то, как вы это делаете, зависит от платформы. В Win32 это с модификатором __stdcall.

Обратите внимание, что вы можете использовать параметр указателя passback-in для "преобразования" таких вызовов в обычные вызовы методов класса. Вот так («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());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...