是否可以在 C++ 类中使用信号?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/343219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:47:11  来源:igfitidea点击:

Is it possible to use signal inside a C++ class?

c++signal-handling

提问by Pablo Herrero

I am doing something like this:

我正在做这样的事情:

#include <signal.h>

class myClass {
public: 
    void myFunction () 
    {
        signal(SIGIO,myHandler);
    }

    void myHandler (int signum)
    {
        /**
        * Handling code
        */
    }

}

I am working on Ubuntu, using gcc.

我正在使用 gcc 在 Ubuntu 上工作。

But it won't compile. It is complaining with:

但它不会编译。它抱怨:

error: the argument with type void (MyClass::)(int)doesn't agree with void (*) (int)

错误:类型的参数void (MyClass::)(int)不符合void (*) (int)

Any clues? Or maybe it is just that I cannot use a signal inside classes? Are signals only allowed in C?

有什么线索吗?或者也许只是我不能在类中使用信号?信号只在 C 中允许吗?

The error message is an approximate translation because my compiler is not in English.

错误消息是近似翻译,因为我的编译器不是英文的。

回答by Luc Touraille

The second parameter of signal should be a pointer to a function accepting an int and returning void. What you're passing to signal is a pointer to a memberfunction accepting an int and returning void (its type being void (myClass::*)(int)). I can see three possibilities to overcome this issue:

信号的第二个参数应该是一个指向接受 int 并返回 void 的函数的指针。您传递给信号的是一个指向成员函数的指针,该成员函数接受一个 int 并返回 void (其类型为void (myClass::*)(int))。我可以看到克服这个问题的三种可能性:

1 - Your method myHandlercan be static: this is great, make it static

1 - 你的方法myHandler可以是静态的:这很好,让它成为静态的

class myClass 
{
  public:
    void myFunction () 
    {
        signal(SIGIO, myClass::myHandler);
    }

    static void myHandler (int signum)
    {
        // handling code
    }
};

2 - Your method shouldn't be static: if you're planning to use signal with only one instance, you can create a private static object, and write a static method that simply call the method on this object. Something along the lines of

2 - 你的方法不应该是静态的:如果你打算只使用一个实例的信号,你可以创建一个私有的静态对象,并编写一个静态方法来简单地调用这个对象上的方法。类似的东西

class myClass 
{
  public:
    void myFunction () 
    {
        signal(SIGIO, myClass::static_myHandler);
    }

    void myHandler (int signum)
    {
        // handling code
    }

    static void static_myHandler(int signum)
    {
        instance.myHandler(signum);
    }

  private:
    static myClass instance;
};

3 - However, if you're planning on using the signal with multiple instances, things will get more complicated. Perhaps a solution would be to store each instance you want to manipulate in a static vector, and invoking the method on each of these :

3 - 但是,如果您计划在多个实例中使用信号,事情会变得更加复杂。也许一个解决方案是将您想要操作的每个实例存储在一个静态向量中,并在每个实例上调用该方法:

class myClass
{
  public:
    void myFunction () // registers a handler
    {
        instances.push_back(this);
    }

    void myHandler (int signum)
    {
        // handling code
    }

    static void callHandlers (int signum) // calls the handlers
    {
        std::for_each(instances.begin(), 
                      instances.end(), 
                      std::bind2nd(std::mem_fun(&myClass::myHandler), signum));
    }
  private:
    static std::vector<myClass *> instances;
};

and somewhere, do a single call to

在某个地方,打一个电话

signal(SIGIO, myClass::callHandlers);

But I think that if you end up using the last solution, you should probably think about changing your handling design :-)!

但我认为,如果您最终使用最后一个解决方案,您可能应该考虑更改您的处理设计:-)!

回答by J?rn Jensen

To pass a pointer to a method, it must be a static method and you must specify the class name.

要传递指向方法的指针,它必须是静态方法并且必须指定类名。

Try this:

尝试这个:

class myClass {
  void myFunction () 
  {
    signal(SIGIO, myClass::myHandler);
  }

  static void myHandler (int signum)
  {
     // blabla
  }
};

And you should also read the link supplied by Baget, the paragraph 33.2 in the C++ FAQ.

您还应该阅读 Baget 提供的链接,即 C++ FAQ 中第 33.2 段

回答by SamB

Actually, C++ signal handlers are not permitted to use any facilities not present in both C and C++ (except that in C++11 they may use atomics), and are required to use C linkage. Quoting C++11 draft n3242section 18.10 "Other runtime support" [support.runtime] (paragraph 8),

实际上,C++ 信号处理程序不允许使用 C 和 C++ 中不存在的任何设施(除了在 C++11 中它们可能使用原子),并且需要使用 C 链接。引用C++11 草案 n3242第 18.10 节“其他运行时支持”[support.runtime](第 8 段),

The common subset of the C and C++ languages consists of all declarations, definitions, and expressions that may appear in a well formed C++ program and also in a conforming C program. A POF (“plain old function”) is a function that uses only features from this common subset, and that does not directly or indirectly use any function that is not a POF, except that it may use functions defined in Clause 29 that are not member functions. All signal handlers shall have C linkage. A POF that could be used as a signal handler in a conforming C program does not produce undefined behavior when used as a signal handler in a C++ program. The behavior of any other function used as a signal handler in a C++ program is implementation-defined.

C 和 C++ 语言的公共子集包括可能出现在格式良好的 C++ 程序和符合标准的 C 程序中的所有声明、定义和表达式。POF(“plain old function”)是仅使用来自该公共子集的特征的函数,并且不直接或间接使用任何不是 POF 的函数,除非它可以使用第 29 条中定义的函数成员函数。所有信号处理程序都应具有 C 链接。可在符合 C 程序中用作信号处理程序的 POF 在用作 C++ 程序中的信号处理程序时不会产生未定义的行为。在 C++ 程序中用作信号处理程序的任何其他函数的行为是实现定义的。

(Clause 29 being the one on atomics.)

(第 29 条是关于原子的。)

回答by gekomad

#include <signal.h>

class myClass {

 private:
  static myClass* me;

 public:
  myClass(){ me=this; }

  void myFunction (){
    signal(SIGIO,myClass::myHandler);
  }

  void my_method(){ }

  static void myHandler (int signum){
    me->my_method();
 }
}

回答by Michael Firth

It does seem crazy that you can post new answers with less reputation than it takes to comment on existing ones, but there we go.

您可以发布声誉低于评论现有答案的新答案似乎很疯狂,但我们走了。

gekomad's answer from Sept 24 2015 was the one that I used to solve my problem. It is worth pointing out that this will only work completely obviously when there is only ever one instance of myClasscreated. otherwise, the static object pointer will point to one of the instances (the most recently created) which may not be the desired one.

gekomad 2015 年 9 月 24 日的回答是我用来解决问题的回答。值得指出的是,只有当只有一个myClasscreated实例时,这才会完全有效。否则,静态对象指针将指向可能不是所需的实例之一(最近创建的)。

And, in case it is useful to someone else, a valid 2018 URL for the FAQ question linked in a couple of the answers is:

而且,如果它对其他人有用,几个答案中链接的常见问题解答问题的有效 2018 URL 是:

http://www.cs.technion.ac.il/users/yechiel/c++-faq/memfnptr-vs-fnptr.html

http://www.cs.technion.ac.il/users/yechiel/c++-faq/memfnptr-vs-fnptr.html