tl;dr:SIGEV_THREAD 不能基于信号工作的基本前提是错误的——信号是产生新线程的底层机制。 glibc 不支持为多个回调重用同一个线程。
timer_create 的行为与您想象的不完全一样 - 它的第二个参数 struct sigevent *restrict sevp 包含字段 sigevent_notify,该字段具有以下 documentation:
SIGEV_THREAD
通过调用 sigev_notify_function "通知进程"
if" 它是一个新线程的启动函数。(在
这里的实现可能性是每个定时器通知
可能会导致创建一个新线程,或者单个线程
被创建用于接收所有通知。) 该函数被调用
以 sigev_value 作为其唯一参数。如果 sigev_notify_attributes 是
不为 NULL,它应该指向一个 pthread_attr_t 结构,该结构定义
新线程的属性(参见 pthread_attr_init(3))。
事实上,如果我们查看 glibc 的 implementation:
else
{
/* Create the helper thread. */
pthread_once (&__helper_once, __start_helper_thread);
...
struct sigevent sev =
{ .sigev_value.sival_ptr = newp,
.sigev_signo = SIGTIMER,
.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID,
._sigev_un = { ._pad = { [0] = __helper_tid } } };
/* Create the timer. */
INTERNAL_SYSCALL_DECL (err);
int res;
res = INTERNAL_SYSCALL (timer_create, err, 3,
syscall_clockid, &sev, &newp->ktimerid);
我们可以看到__start_helper_thread的implementation:
void
attribute_hidden
__start_helper_thread (void)
{
...
int res = pthread_create (&th, &attr, timer_helper_thread, NULL);
然后关注timer_helper_thread的implementation:
static void *
timer_helper_thread (void *arg)
{
...
/* Endless loop of waiting for signals. The loop is only ended when
the thread is canceled. */
while (1)
{
...
int result = SYSCALL_CANCEL (rt_sigtimedwait, &ss, &si, NULL, _NSIG / 8);
if (result > 0)
{
if (si.si_code == SI_TIMER)
{
struct timer *tk = (struct timer *) si.si_ptr;
...
(void) pthread_create (&th, &tk->attr,
timer_sigev_thread, td);
所以 - 至少在 glibc 级别 - 当使用 SIGEV_THREAD 时,您必然使用信号来向线程发出信号以创建函数 - 而且您的主要动机似乎是避免使用警报信号。
在 Linux 源代码级别,计时器似乎只处理信号 - kernel/time/posix_timers.c 中的 posix_timer_event 函数(由 kernel/time/alarmtimer.c 中的 alarm_handle_timer 调用)直接进入 signal.c 中的代码,这必然会发送一个信号。因此,在使用timer_create 时似乎无法避免信号,并且您的问题中的这个语句 - “当计时器到期时,这将在线程上触发回调,而不是向进程发送 SIGALRM 信号。” - 是假的(虽然信号不一定是SIGALRM)。
换句话说 - 与信号相比,SIGEV_THREAD 似乎没有性能优势。信号仍将用于触发线程的创建,并且您正在增加创建新线程的额外开销。