当前位置: 首页 > 知识库问答 >
问题:

中断线程内的选择、睡眠和类似的阻塞功能(pthread)。线程中的信号

闾丘昊然
2023-03-14

我有一个接受连接的服务器套接字线程。它使用超时1秒的选择来做其他事情。然而,有时我想在特定信号从外部到达应用程序时立即做这些事情。在单线程程序中,信号会中断睡眠和定时IO阻塞功能,如选择。然而,在主信号以外的线程中,不会中断睡眠。

我可以使用pthread_kill()从主线程发出信号,并且睡眠被中断,但是当信号来自外部时,它不会中断线程中的睡眠。如果我安装一个处理程序,并在处理程序内部调用pthread_kill(),处理程序将捕获信号并进入无限循环。

如何通过程序外部的信号中断睡眠?例如SIGUSR1。

我可以这样做:我可以启动另一个线程来做我在服务器线程中做的其他事情。它会等待一个条件,然后主线程会向等待线程发送一个信号。但是我真的想知道如何中断其他线程的睡眠/选择——例如,为了更快地关机,我想中断所有等待,让线程更快地退出。我还想了解信号在其他线程中是如何工作的。有时你想中断一个不在你的代码中的睡眠(另一个库)

我读到了pthread_sigmask(),但我不确定我理解了它。在主线程中,安装了处理程序来处理信号。其他线程中会发生什么?这个例子使用sigwait()来接收信号。如果不调用sigwait会怎么样?信号是累积在一个队列中,还是它们对不等待它们的线程没有影响?

共有1个答案

谷梁英毅
2023-03-14

这是我想到的。我不知道是否有其他解决方案。我会等待建议。

为了发出需要完成工作的信号,SIGUSR1被发送到程序。它向线程发送SIGALERT,使它们中断阻塞代码,如sleep、select等。作为副作用,主线程中的阻塞也会被中断,即使信号只发送给其他线程。

它不能只用一个信号来完成 - 就像处理sigalert然后使用pthread_kill信号提醒其他两个线程一样,因为它进入了一个无限循环。

#include <stdio.h>
#include <stdlib.h> // EXIT_FAILURE
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h> // for errno
#include <pthread.h>

#ifndef __cplusplus
#define true 1
#define false 0
#define nullptr NULL
typedef int bool;
#endif

// I copied this. I don't know why it's in a loop
#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

pthread_t t1;
pthread_t t2;
pthread_t st;
pthread_t mainThreadId; // main thread

void *workerThread(void * param);
void unblockSignals();
void alertSignaHlandler(int sigNum);
void installSignalHandler(int sigNum, __sighandler_t handler);

void sigUsr1Handler(int sigNum) {
  pthread_kill(t1, SIGALRM);
//  pthread_kill(t2, SIGALRM); // let's say we only want t1 to interrupt
}

// on SIGTERM we want all threads to interrupt sleep so they can quit faster
void sigTermHandler(int sigNum) {
  // setRunning(false); // also implement a global running vairable with a mutex, that other threads check to quit
  pthread_kill(t1, SIGALRM);
  pthread_kill(t2, SIGALRM);
//  pthread_kill(mainThreadId, SIGALRM); // main thread will be interrupted by the signal anyway.
}

void alertSignaHlandler(int sigNum) {}

int main() {
  void * ret1;
  void * ret2;

  mainThreadId = pthread_self();

  printf("main starting with pid %d\n", getpid());

  installSignalHandler(SIGALRM, alertSignaHlandler); // we need this to prevent program termination on alarm
  installSignalHandler(SIGUSR1, sigUsr1Handler); // send this signal to interrupt other threads
  installSignalHandler(SIGTERM, sigTermHandler);
  installSignalHandler(SIGINT, sigTermHandler);

  pthread_create(&t1, NULL, &workerThread, (void *)1);
  pthread_create(&t2, NULL, &workerThread, (void *)2);

  // simulate work in main thread. Only interrupt this on SIGTERM or SIGINT (ctrl-c)
  time_t ts = time(NULL);
  sleep(20);
  ts = time(NULL) - ts;
  printf("main(): sleep took %lds\n", ts);


  pthread_join(t1, &ret1);
  pthread_join(t2, &ret2);

  printf("main thread reached end\n");

  return 0;
}

void *workerThread(void * param){
  long id = (long) param;

  printf("workerThread %d starting...\n", id);

  // in the real world this will be in a loop. somethign like this
  //  while(running) {
  //    // do something every minute
  //    doSomething();
  //    sleep(60); // this sleep we want to interrupt, because we don't want to wait 60 seconds to exit
  //  }

  time_t ts = time(NULL);
  sleep(60); // this can also be select, read or other timed blocking call.
  ts = time(NULL) - ts;
  printf("workerThread(%ld): sleep took %lds\n", id, ts);

  return NULL;
}

void installSignalHandler(int sigNum, __sighandler_t handler){
  struct sigaction newAction, oldAction;

  memset(&newAction, '\0', sizeof(newAction));
  newAction.sa_flags = 0;
  //newAction.sa_flags = SA_RESETHAND;
  newAction.sa_handler = handler;
  sigaction(sigNum, &newAction, &oldAction);
}
 类似资料:
  • 我使用 C 和 POSIX 线程创建了一个多线程应用程序。我现在应该阻塞一个线程(主线程),直到设置了布尔标志(变为真)。 我找到了两种方法来完成这件事。 > 在没有睡眠的情况下旋转。 在睡眠中旋转循环。 如果我应该遵循第一种方式,为什么有些人编写代码遵循第二种方式?如果应该使用第二种方法,为什么要让当前线程Hibernate呢?这种方式的缺点是什么?

  • 我正在编写一个有3个线程的程序。一个读取一个文本文件并将单词输入到大小为2的ArraylistBlockingQueue中。下一个获取该列表并反转其中的每个其他单词。最后一个线程获取单词并将它们写入一个新的文本文件。 我所有的东西都在工作,除了我不知道如何中断和停止我的线程。程序写入文本文件,但从未结束。 主要方法 输入 反向类@重写公共void run(){ 输出代码@覆盖公共无效run(){

  • 问题内容: 首先,我想说的是,我知道这个方法是错误的,因此,我出于好奇而问这个问题。可以说我有一个这样的秋千应用程序: 基本上,当我单击按钮时,我期望图像显示,然后GUI冻结2秒钟,然后我期望图像显示。但是发生的是:我单击按钮,GUI冻结2秒钟并显示。没有之前。但是让我感到困惑的是当我把它们和。因此,当我单击按钮时,它会打印“郁金香画”,并在2秒钟后打印“考拉画”。有人可以告诉我这是怎么回事吗?问

  • 我是一个初学者,我试图重现一个rae条件,以便使自己熟悉这个问题。为此,我创建了以下程序: 我在线程的函数中添加了睡眠,以便重现竞争条件,因为,我是如何理解的,如果我只是添加一个作为工作负载,竞争条件不会表现出来:创建了一个线程,然后它运行工作负载,并且它恰好在另一个迭代中创建的另一个线程开始其工作负载之前完成。我的问题是工作负载中的睡眠()似乎被忽略了。我将参数设置为5sec,我希望程序至少运行

  • 编辑: 主要问题:为什么只有一个线程抛出interruptedexception,而两个线程都阻塞在条件上。await 所以下面的代码只是我创建的一个示例。主要的问题是开发一个生产者-消费者实现,在这个实现中,我必须创建一个模拟类,它产生两种线程:客户线程和厨师线程,这两种线程是基于可重入锁进行同步的。在执行一些操作(客户添加订单,厨师执行服务这些订单)后,我调用客户线程上的join以确保所有订单

  • 问题内容: 我的应用程序正在发生什么是有道理的,但我不知道如何解决。这是我的应用程序的简要说明:计时器窗​​口应显示在屏幕的右下角,并显示实时时间。一个小时后,它应该执行一些操作(我还没有决定要执行的操作)。我面临的问题是,在 Timer.java中, 当我刷新实时计时器的秒数时,我正在使用线程睡眠,这阻止了我的所有应用程序继续执行,因此没有窗口显示。 这是带有一些注释的代码: TimerFram