【问题标题】:Does timer_create create new thread for handlertimer_create 是否为处理程序创建新线程
【发布时间】:2017-03-14 04:52:13
【问题描述】:

timer_settime() 每秒构建计时器。信号处理程序是traffic_measurement_handlertraffic_measurement_handler 是否在新线程中运行?处理程序运行时如何让callback停止?

#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;

int main(void)
{
    ..

    build_timer();
    pcap_loop(pcap_handle, -1, callback, NULL);
}

void callback() // callback of Libpcap API: pcap_loop()
{
    detect_network_traffic(); // stop when timer expires, and then continue                 
                              // to run when traffic_measurement_handler has finished.
}

// timer handler runs every second to update database
void traffic_measurement_handler() 
{
    .. // This block will fetch global variables, so I want to
       // let callback stop when this handler is running.


    // rebuild the timer
    build_timer();

}

// set timer
void build_timer()
{
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = traffic_measurement_handler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIG, &sa, NULL);

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = &timerid;
    timer_create(CLOCKID, &sev, &timerid);

    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = its.it_value.tv_sec;
    its.it_interval.tv_nsec = its.it_value.tv_nsec;

    timer_settime(timerid, 0, &its, NULL);
}

信号处理程序在只存在一个线程的进程中是否安全?

添加:第二版
是这样吗?

pthread_t thread_global;

int main(void)
{
    // register SIGUSR1 handler
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = traffic_measurement_handler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIG, &sa, NULL);

    pthread_create(&thread1, NULL, processing_thread, (void *) thread_id1);
    pthread_create(&thread2, NULL, timer_thread, (void *) thread_id2);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);    
}

void *processing_thread(void *thread_id)
{
    pcap_loop(pcap_handle, -1, callback, NULL);
}

void callback() // callback of Libpcap API: pcap_loop()
{
    thread_global = pthread_self();
    detect_network_traffic(); // stop when SIGUSR1 is caught, and then continue                 
                              // to run when traffic_measurement_handler has finished.
}

//update database every second when SIGUSR1 is caught
void traffic_measurement_handler()
{
    ..
}

//This thread is used to notify updating database every second.
void *timer_thread(void *thread_id)
{
    for (; ;) {
        sleep(1);
        pthread_kill(thread_global, SIGUSR1);
    }
}

【问题讨论】:

  • 这取决于您传递给timer_create 的参数值。阅读timer_create man page。它告诉您如何根据参数调用函数。如果您需要进一步的帮助,请显示minimal reproducible example
  • @kaylum 我已经添加了示例代码。
  • 如果将 sigev_notify 设置为 SIGEV_THREAD 而不是 SIGEV_SIGNAL,则回调将作为新线程运行。现在它作为信号处理程序运行。
  • @Ali Volkan ATLI,谢谢。那么callbacktraffic_measurement_handler 在同一个线程中吗?
  • @hel,还是不行,2.6 posix线程,信号被发送到进程,由根线程接收和处理。 pcap_loop 创建另一个线程,所以它会在不同的线程上

标签: c linux


【解决方案1】:
  1. traffic_measurement_handler 是否在新线程中运行?

POSIX threads 中,当sigev_notify = SIGEV_SIGNAL 出现信号时,不会创建新线程。因此,在您的代码中,您不会创建新线程。

  1. 如何在处理程序运行时让回调停止?

您可以将信号设置为由运行回调的同一线程处理。

POSIX.1 区分了定向到整个进程的信号和定向到单个线程的信号的概念。

阅读Unix pthreads and signals: per thread signal handlers

【讨论】:

  • 是的。 sigev_notify = SIGEV_SIGNAL。如果这不创建新线程,则整个进程只有一个线程。
  • 那个图书馆怎么样?您给它一个回调,它会在发生某些事情时运行该回调(我不知道那个库)。然后在该库的不同线程中运行一个事件处理程序。
【解决方案2】:

要将定时器处理程序作为线程模式运行,您必须修改 sev.sigev_notify; 的值 从timer_create 的手册页中阅读以下引用

sevp.sigev_notify 字段可以有以下值:

   SIGEV_NONE
          Don't asynchronously notify when the timer expires.  Progress
          of the timer can be monitored using timer_gettime(2).

   SIGEV_SIGNAL
          Upon timer expiration, generate the signal sigev_signo for the
          process.  See sigevent(7) for general details.  The si_code
          field of the siginfo_t structure will be set to SI_TIMER.  At
          any point in time, at most one signal is queued to the process
          for a given timer; see timer_getoverrun(2) for more details.

   SIGEV_THREAD
          Upon timer expiration, invoke sigev_notify_function as if it
          were the start function of a new thread.  See sigevent(7) for
          details.

   SIGEV_THREAD_ID (Linux-specific)
          As for SIGEV_SIGNAL, but the signal is targeted at the thread
          whose ID is given in sigev_notify_thread_id, which must be a
          thread in the same process as the caller.  The
          sigev_notify_thread_id field specifies a kernel thread ID,
          that is, the value returned by clone(2) or gettid(2).  This
          flag is intended only for use by threading libraries.

   Specifying sevp as NULL is equivalent to specifying a pointer to a
   sigevent structure in which sigev_notify is SIGEV_SIGNAL, sigev_signo
   is SIGALRM, and sigev_value.sival_int is the timer ID.

同时查看timer_settimeman的手册页

这里callback 将充当不同的线程,因为pcap_loop 创建了一个新线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多