设置计时器、SIGALRM 和多线程进程(linux,c)

发布于 2024-08-27 17:09:12 字数 534 浏览 3 评论 0原文

我想在带有支持 NPTL 的 libc 的 linux 2.6+ 的多线程进程中使用 setitimer() (或者可能性较小的 alarm())。哪个线程将从内核接收sigalarm (SIGALRM)

谢谢。

2014-04 更新:如果我想编写像 gperftools 的 cpuprofile 这样的分析实用程序,我应该如何在多线程程序中设置 setitimer() ;但在我的工具中,我想支持动态链接程序(因此可以将我自己的库注入到初始化分析中)和静态链接程序(无法执行^^^^^^)。

我当前的分析工具可以在 fork() 之后和 exec() 之前设置 setitimer,并且还使用 ptrace code> 来控制目标程序并劫持由 setitimer 生成的 SIGPROF/SIGVPROF/SIGALRM。我不知道它如何与多线程程序一起工作。

I want to use setitimer() (or less probable, the alarm()) in multithreaded process in linux 2.6+ with NPTL-enabled libc. Which thread will receive sigalarm (SIGALRM) from kernel?

Thanks.

2014-04 update: How should I set the setitimer() in multithreaded program, if I want to write a profiling utility like gperftools's cpuprofile; but in my tool I want to support both dynamically linked programs (so it is possible to inject my own library to init profiling) and statically linked programs (without the possibility of doing ^^^^^^).

My current profiling tool works with setting setitimer just after fork() and before exec(), and it also uses ptrace to get control over the target program and to hijack SIGPROF/SIGVPROF/SIGALRM generated by the setitimer. I have no exact idea how it works with multithreaded programs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

臻嫒无言 2024-09-03 17:09:12

来自 signal(7) 手册页:

进程导向的信号可能是
传递到任一线程
目前还没有
信号受阻。如果超过一个
线程的信号已解锁,
然后内核选择任意一个
向其传递信号的线程。

现在, alarm(2) 手册页显示:

alarm() 安排 SIGALRM 信号
交付给流程
秒秒。

因此,信号被传递到进程(信号也可能指向某个线程),因此您不知道哪个线程将接收它。

setitimer(2) 相同:

当任何计时器到期时,都会发出信号
发送到进程和计时器
(可能)重新启动。

您可以在除一个线程之外的所有线程中阻止 SIGALARM ,然后您可以确定它将被传递到唯一的线程。假设您使用 pthread,您可以使用 pthread_sigmask() 阻止信号。

From signal(7) man page:

A process-directed signal may be
delivered to any one of the threads
that does not currently have the
signal blocked. If more than one of
the threads has the signal unblocked,
then the kernel chooses an arbitrary
thread to which to deliver the signal.

Now, alarm(2) man page says that:

alarm() arranges for a SIGALRM signal
to be delivered to the process in
seconds seconds.

So, the signal is delivered to a process (a signal might be directed at certain thread too) and thus you do not know which of the threads will receive it.

The same with setitimer(2):

When any timer expires, a signal is
sent to the process, and the timer
(potentially) restarts.

You could block SIGALARM in all your threads except one, then you could be certain that it will be delivered to that only thread. Assuming you are using pthreads, you can block signals with pthread_sigmask().

旧话新听 2024-09-03 17:09:12

2010 年 LKML 有一个有趣的话题 https://lkml.org/lkml/2010/4 /11/81:“setitimer 与线程:SIGALRM 返回到哪个线程?(进程主进程或单个子进程)”,作者:Frantisek Rysanek (cz)。作者表示 setitimer 至少在 Fedora 5 之前使用了每线程信号:

... setitimer() 具有每线程粒度。它用于将 SIGALRM 从计时器传递到调用 setitimer() 的特定线程。

但在最近的 Fedora 中,行为发生了变化(“man pthreads”,...“线程不共享间隔计时器(在内核 2.6.12 中修复)。”

在该主题中,Andi Kleen ( Intel) 建议切换到POSIX 计时器 (timer_create)";在 ML 线程中,Davide Libenzi 建议使用 timerfd (timerfd_create、timerfd_settime)在非古老的 ​​Linux 上。

There was interesting topic in LKML in 2010 https://lkml.org/lkml/2010/4/11/81: "setitimer vs. threads: SIGALRM returned to which thread? (process master or individual child)" by Frantisek Rysanek (cz). Author says that setitimer used per-thread signals at least in times before Fedora 5:

... setitimer() had per-thread granularity. It used to deliver a SIGALRM from the timer to the particular thread that called setitimer().

But in more recent Fedoras the behavior was changed ("man pthreads", ..."Threads do not share interval timers (fixed in kernel 2.6.12).")

In the topic, Andi Kleen (Intel) recommends to switch to "POSIX timers (timer_create)"; and in ML thread Davide Libenzi suggests use of timerfd (timerfd_create, timerfd_settime) on non-ancient Linuxes.

燕归巢 2024-09-03 17:09:12

我读过很多帖子,但我还没有找到信号到底是如何工作的。我通常使用pause()来等待信号。但这不起作用,因为无法排除 SIGALARM 并且pause() 不返回信号。这就是为什么它只适用于 sigwait。经过几次尝试,我想出了这个解决方案。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>//"-lpthread" linker option needed

pthread_t thr1;

//wait for all, except SIGALRM
int sigwaitexcludealarm()
{   sigset_t set;
    sigfillset(&set);
    sigdelset(&set,SIGALRM);
    int sig=0;
    sigwait(&set,&sig);
    return sig;
}

//simple one shot timer
void dotimer(int sig)
{   printf("ALARM!\n");
    struct itimerval timerval;
    timerval.it_value.tv_sec=0;
    timerval.it_value.tv_usec=500000;//0,5 sec
    timerval.it_interval.tv_sec=0;
    timerval.it_interval.tv_usec=0;
    setitimer(ITIMER_REAL, &timerval, NULL);
}

//timer thread worker
void* timer_run(void* p)
{   printf("thread start\n");
    signal(SIGALRM, dotimer);
    dotimer(0);
    sigwaitexcludealarm();
    printf("thread finished\n");
}

//do shutdown
void doeshutdown(int sig)
{   pthread_kill(thr1,sig);
    pthread_join(thr1,NULL);
    printf("shutdown done\n");
}

//signal handler, needed but never called
void donop(int sig)
{   return;
}


int main(int argc, char** argv)
{   printf("main start\n");
    pthread_create(&thr1,NULL,timer_run,NULL);
    //connecting signals to this process
    signal(SIGINT, donop);
    signal(SIGTERM, donop);
    signal(SIGKILL, donop);
    doeshutdown(sigwaitexcludealarm());
    printf("main exit\n");
    return 0;
}

I've read many posts but I haven't found how the signals work exactly. I usually use pause() to wait for a signal. But that doesn't work because SIGALARM can't be excluded and pause() doesn't return a signal. That's why it only works with sigwait. After a few tries I came up with this solution.

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>//"-lpthread" linker option needed

pthread_t thr1;

//wait for all, except SIGALRM
int sigwaitexcludealarm()
{   sigset_t set;
    sigfillset(&set);
    sigdelset(&set,SIGALRM);
    int sig=0;
    sigwait(&set,&sig);
    return sig;
}

//simple one shot timer
void dotimer(int sig)
{   printf("ALARM!\n");
    struct itimerval timerval;
    timerval.it_value.tv_sec=0;
    timerval.it_value.tv_usec=500000;//0,5 sec
    timerval.it_interval.tv_sec=0;
    timerval.it_interval.tv_usec=0;
    setitimer(ITIMER_REAL, &timerval, NULL);
}

//timer thread worker
void* timer_run(void* p)
{   printf("thread start\n");
    signal(SIGALRM, dotimer);
    dotimer(0);
    sigwaitexcludealarm();
    printf("thread finished\n");
}

//do shutdown
void doeshutdown(int sig)
{   pthread_kill(thr1,sig);
    pthread_join(thr1,NULL);
    printf("shutdown done\n");
}

//signal handler, needed but never called
void donop(int sig)
{   return;
}


int main(int argc, char** argv)
{   printf("main start\n");
    pthread_create(&thr1,NULL,timer_run,NULL);
    //connecting signals to this process
    signal(SIGINT, donop);
    signal(SIGTERM, donop);
    signal(SIGKILL, donop);
    doeshutdown(sigwaitexcludealarm());
    printf("main exit\n");
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文