跟进问题:这个问题 https://stackoverflow.com/questions/1223040/c-timers-in-unix
如链接问题中所述,我们有一个 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。不是一个复杂的概念。我想知道的是,FunctionName 是否会同时在 start() 函数和回调中调用?这可能会导致我的一些内存损坏,因为它们访问非线程安全的共享内存。
我的测试告诉我,它们确实在不同的线程中运行(仅当我使用事件时才会损坏),即使:cout<<pthread_self()<<endl;
说他们有相同的线程ID。
有人可以向我解释这些回调是如何分叉的吗?他们按什么顺序执行?他们在什么线程中运行?我假设它们在执行 select() 的线程中运行,但是它们什么时候获得相同的线程 ID?
真正的答案取决于 Timer 的实现,但如果您从同一线程运行回调,则很可能使用signals http://linux.die.net/man/2/signal or POSIX定时器 http://linux.die.net/man/2/timer_create。无论哪种方式,select() http://linux.die.net/man/2/select根本不参与。
对于信号和 posix 定时器,您可以从信号处理程序中安全地执行很少的操作。仅某些特定的信号安全调用,例如read() http://linux.die.net/man/2/read and write() http://linux.die.net/man/2/write (NOT允许使用 fread() 和 fwrite(),甚至 new 和 cout)。通常我们会做的是将 write() 写入pipe http://linux.die.net/man/2/pipe or eventfd http://linux.die.net/man/2/eventfd,然后在另一个线程或运行 select() 的主事件循环中,注意此通知并处理它。这允许您以安全的方式处理信号。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)