【问题标题】:How Operating System callbacks work操作系统回调如何工作
【发布时间】:2009-08-05 15:21:31
【问题描述】:

跟进问题: This question

如链接问题中所述,我们有一个 API,它使用轮询 select() 的事件外观来处理用户定义的回调。

我有一个这样的课程:

class example{
 public:
    example(){
        Timer* theTimer1 =  Timer::Event::create(timeInterval,&example::FunctionName);
        Timer* theTimer2 =  Timer::Event::create(timeInterval,&example::FunctionName);
        start();
       cout<<pthread_self()<<endl;
    }
  private:
     void start(){
        while(true){
           if(condition)
              FunctionName();
           sleep(1);
        }
     }
     void FunctionName(){
         cout<<pthread_self()<<endl;
         //Do stuff
     }
};

这背后的想法是,如果条件为真或计时器到时,您希望 FunctionName 被调用。不是一个复杂的概念。我想知道的是,是否会在 start() 函数和回调中同时调用 FunctionName ?这可能会对我造成一些内存损坏,因为它们访问的是非线程安全的共享内存。

我的测试告诉我,它们确实在不同的线程中运行(仅当我使用事件时才会损坏),即使:cout&lt;&lt;pthread_self()&lt;&lt;endl; 表示它们具有相同的线程 ID。

有人可以向我解释这些回调是如何分叉的吗?他们执行的顺序是什么?他们在什么线程中运行?我假设它们在执行 select() 的线程中运行,但是它们何时获得相同的线程 ID?

【问题讨论】:

  • 应标记为 C 而不是 C++
  • @Tom,代码示例明显是C++...

标签: c++ c unix posix


【解决方案1】:

真正的答案取决于 Timer 的实现,但如果您从同一个线程运行回调,则最有可能使用signalsposix timers。不管怎样,select() 根本不参与。

使用信号和 posix 计时器,您可以从信号处理程序中安全地做的事情很少。只允许使用某些特定的信号安全调用,例如read()write()NOT fread() 和 fwrite(),甚至 new 和 cout)。通常人们会做的是 write() 到 pipeeventfd,然后在另一个线程中,或者你的主事件循环运行 select(),注意这个通知并处理它。这使您可以安全地处理信号。

【讨论】:

  • 你是对的。 Select 之所以存在,是因为 Event api 处理 select() 事件以及 Timers。 >.
  • 顺便说一句,使用信号的 api 使用起来确实相当痛苦。鼓励任何人在线程中将这些回调作为常规函数运行,这样他们只需要锁定:)
  • 现在我只是用我自己的事件循环来规避这个问题。讨厌,我知道,但至少我可以正确地让它们线程安全......
【解决方案2】:

您编写的代码不会编译,更不用说运行了。 Example::FunctionName 需要是静态的,并且需要一个对象引用作为回调函数。

如果计时器在不同的线程中运行,则此函数可能会被三个不同的线程调用。

【讨论】:

    猜你喜欢
    • 2010-10-06
    • 2010-11-18
    • 2016-01-01
    • 2011-09-08
    • 1970-01-01
    • 2015-09-24
    • 2013-02-12
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多