【问题标题】:Using SIGUSR1 and SIGUSR2 as signals in pthread_kill()在 pthread_kill() 中使用 SIGUSR1 和 SIGUSR2 作为信号
【发布时间】:2011-09-17 21:23:56
【问题描述】:

我想使用 SIGUSR1 和 SIGUSR2 作为 pthread_kill() 的参数来暂停正在运行的线程的执行(即线程向自身发送信号)并在满足条件时由对等线程恢复暂停的线程。 将不胜感激任何指针,如示例代码或有关它的视图。

谢谢

【问题讨论】:

  • 您几乎肯定希望为此使用互斥锁和条件变量而不是信号...
  • 家庭作业?如果是,请相应地标记。
  • 确实,为此目的,信号是绝对错误的。
  • @Heandel..不,这不是功课
  • @Nemo...谢谢..我现在将使用互斥锁和条件变量,但只是想调查一下我的选择。在“使用 POSIX 线程编程”一书中遇到了使用上述信号暂停和恢复线程的部分代码,并希望有经验的程序员提供意见。

标签: c linux pthreads


【解决方案1】:

信令用作以下示例。但是,在您的情况下,您需要条件变量 https://computing.llnl.gov/tutorials/pthreads/#ConVarSignal有例子

 pthread_cond_wait (condition,mutex)
 pthread_cond_signal (condition)
 pthread_cond_broadcast (condition)

pthread_kill() 正确使用信号的示例如下所示

 /* ptsig.c
   This program illustrates the use of signals in threads.

   Three threads including the main thread.
   main thread
     a. Set up a signal mask to block all signals.
     b. Set up signal handlers for SIGINT and SIGUSR1.
     c. Create thread_1, detached.
     d. Create thread_2, nondetached.
     e. Send SIGINT & SIGUSR1 to thread_1.
     f. Quit.

   thread_1
     a. Unblock all to embrace all signals.
     b. Wait for signals.
     c. Send SIGINT and SIGUSR1 to thread_2
     d. Wait for thread_2 to terminate
     e. Print thread_2 return status.
     f. Quit

   thread_2
     a. Unblock SIGUSR1 -- all others blocked due to inheritance.
     b. Wait for signals.
     c. Quit

   Note: There is hardly any error checking in this example -- not a good
   idea, but to make the program a bit more easier to explain.

   To compile:  gcc  ptsig.c -lpthread 
                                                   Sam Hsu (11/19/10)
*/

#define _POSIX_C_SOURCE 199506L
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>

pthread_t tid2;
static void int_handler(int signo), usr1_handler(int signo);

void millisleep(int milliseconds)
{
      usleep(milliseconds * 1000);
}

main()
{
   pthread_t tid1;
   pthread_attr_t attr_obj;             /* a thread attribute variable */
   void *thread_1(void *), *thread_2(void *);
   sigset_t sigmask;                 
   struct sigaction action;

   /* set up signal mask to block all in main thread */
   sigfillset(&sigmask);                /* to turn on all bits */
   pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0);

   /* set up signal handlers for SIGINT & SIGUSR1 */
   action.sa_flags = 0;
   action.sa_handler = int_handler;
   sigaction(SIGINT, &action, (struct sigaction *)0);
   action.sa_handler = usr1_handler;
   sigaction(SIGUSR1, &action, (struct sigaction *)0);

   pthread_attr_init(&attr_obj);        /* init it to default */
   pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_DETACHED);
   pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL);
   printf("TID(%u) created\n", (unsigned int)tid1);

   pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_JOINABLE);
   pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL);
   printf("TID(%u) created\n", (unsigned int)tid2);
   millisleep(1000);     /* for some reason a sleep is needed here */

   printf("main(%u) sending SIGINT to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
   pthread_kill(tid1, SIGINT);          /* not blocked by tid1 */
   printf("main(%u) sending SIGUSR1 to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
   pthread_kill(tid1, SIGUSR1);         /* not blocked by tid1 */

   printf("main(%u) is terminating\n", (unsigned int)pthread_self());
   pthread_exit((void *)NULL);          /* will not terminate process */
}  /* main */

void *thread_1(void *dummy)
{                               
   int sig, status, *status_ptr = &status;
   sigset_t sigmask;

   sigfillset(&sigmask);                /* will unblock all signals */  
   pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
   sigwait(&sigmask, &sig);
   switch(sig) {
     case SIGINT:
         int_handler(sig);
         break;
     default:   
         break;
   }
   printf("TID(%u) sending SIGINT to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
   pthread_kill(tid2, SIGINT);          /* blocked by tid2 */
   printf("TID(%u) sending SIGUSR1 to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
   pthread_kill(tid2, SIGUSR1);         /* not blocked by tid2 */

   pthread_join(tid2, (void **)status_ptr);
   printf("TID(%u) exit status = %d\n", (unsigned int)tid2, status);  

   printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
   pthread_exit((void *)NULL);          /* calling thread will terminate */
}  /* thread_1 */

void *thread_2(void *dummy)
{                               
   int sig;
   sigset_t sigmask;

   sigemptyset(&sigmask);               /* to zero out all bits */
   sigaddset(&sigmask, SIGUSR1);        /* to unblock SIGUSR1 */  
   pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
   sigwait(&sigmask, &sig);
   switch(sig) {
     case SIGUSR1: 
         usr1_handler(sig);
         break;
     default:     
         break;
   }
   printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
   pthread_exit((void *)NULL);          /* calling thread will terminate */
}  /* thread_2 */

static void int_handler(int dummy)
{
   printf("SIGINT received by TID(%u)\n", (unsigned int)pthread_self());
}  /* int_handler */

static void usr1_handler(int dummy)
{
   printf("SIGUSR1 received by TID(%u)\n", (unsigned int)pthread_self());
}  /* usr1_handler */

pthread_cancel() 相对于 pthread_kill() 更安全

pthread_cancel() 示例如下

#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#define handle_error_en(en, msg) \
       do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void *
thread_func(void *ignored_argument)
{
    int s;
    s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_setcancelstate");

    while (1) {
        printf("sleeping\n");

        sleep(1);        /* Should get canceled while we sleep */

    }

    /* sleep() is a cancellation point */


    /* Should never get here */

    printf("thread_func(): not canceled!\n");
    return NULL;
}

int
main(void)
{
    pthread_t thr;
    void *res;
    int s;

    /* Start a thread and then send it a cancellation request */

    s = pthread_create(&thr, NULL, &thread_func, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");

    sleep(10);           /* Give thread a chance to get started */

    printf("main(): sending cancellation request\n");
    s = pthread_cancel(thr);
    if (s != 0)
        handle_error_en(s, "pthread_cancel");

    /* Join with thread to see what its exit status was */

    s = pthread_join(thr, &res);
    if (s != 0)
        handle_error_en(s, "pthread_join");

    if (res == PTHREAD_CANCELED)
        printf("main(): thread was canceled\n");
    else
        printf("main(): thread wasn't canceled (shouldn't happen!)\n");
    exit(EXIT_SUCCESS);
}

【讨论】:

    【解决方案2】:

    虽然我同意 Nemo,但有一些通过信号挂起线程的有效用例。 PWPT 中的susp.c 代码当然是一个很好的基础,但您也可以在GLIBC 中找到它。您可能还希望将线程从阻塞 IO 系统调用中中断(参见 this question)或中断信号量等待(参见 this question)。

    【讨论】:

    • 所有这些示例本质上都有竞争条件。 (也就是说,您可以在目标线程设法进入阻塞系统调用之前发送信号。)这种竞争条件实际上不可能100% 确定地修复,因为在线程说“我现在要阻塞”以及它实际进入阻塞调用的时间。只是不要这样做。 (例外:sigsuspend(),它以原子方式更改信号掩码并等待。不过,最好重写代码以使用正确的线程原语。)
    • @Nemo - 正如我一开始所说的:我同意你的看法。您几乎应该总是使用互斥体/条件变量。但我认为你应该小心绝对。 pthread_kill() 有有效的用例。
    • 我同意总是有例外(因此在我的评论中使用“几乎肯定”),但在这种情况下,我认为它们比大多数熟练的程序员所意识到的还要罕见。恰当的例子:你的例子:-)。
    猜你喜欢
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 2013-07-16
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多