gpt4 book ai didi

c - 如何唤醒正在 sleep (3)的线程

转载 作者:行者123 更新时间:2023-11-30 20:11:54 36 4
gpt4 key购买 nike

我想打破sleep (3)在我的主线程的另一个线程中。为此,我想使用 raise (sig)并在中断该系统调用后继续执行代码。

那么,我应该使用哪个信号来引起 sleep并返回EINTR

到目前为止我编写的代码:

void *event_loop (void *threadid)
{
int rc;
long tid;
do{
rc = sleep(20);
printf ("return from sleep with %d", rc);
fprintf(stderr, "Value of errno: %d\n", errno);
} while (errno == EINTR);
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld! = %d\n", tid);

}

void main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
int sig=SIGABRT ; // which signal???
int i=0;
printf("Main THREAD\n");
for(t=0;t<2;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, event_loop, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
sleep(2);
printf("rasing signal now from main thread...\n");
raise(sig);
pthread_exit(NULL);
}

最佳答案

这不是一个中断阻塞系统调用的信号;正是将信号传送到注册处理程序(未使用 SA_RESTART 标志安装)会导致阻塞系统调用中断。

这是一个例子。第一个函数是一个空信号处理程序(长格式,因此适用于 POSIX 信号以及实时信号 SIGRTMIN+0SIGRTMAX-1)。第二个函数是处理程序安装程序。

#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>

static void empty_handler(int signum, siginfo_t *info, void *context)
{
}

/* Install empty handler for the specified signal.
* Returns 0 if success, errno error code otherwise.
*/
static int install_empty_handler(const int signum)
{
struct sigaction act;

memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_sigaction = empty_handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(signum, &act, NULL) == -1)
return errno;

return 0;
}

在您的 main() 中,假设您运行

    if (install_empty_handler(SIGUSR1)) {
fprintf(stderr, "Cannot install signal handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

在创建任何线程之前。 (信号处理程序始终分配给进程中的所有线程;您不能为一个线程设置一个处理程序,为另一个线程设置另一个处理程序。您可以在已安装的处理程序中检查当前线程 ID,并根据它执行操作。因此,您不需要在创建线程之前安装它们;只是在创建线程之前安装处理程序更容易维护,并且留下更少的竞争窗口。)

假设您有 pthread_t somethread;,其中 somethread 包含阻塞系统调用中线程的线程标识符。

如果您从任何线程调用,

pthread_kill(somethread, SIGUSR1);

SIGUSR1 信号被发送到该线程。

(请注意,pthread_kill() 调用将立即返回,并且您不能假设此时信号已传递。如果您也想要传递通知,则需要其他机制。此外,信号首先被传递;阻塞系统调用仅在传递之后被中断,并且如果系统负载很重,则在信号传递之间可能存在可测量的延迟。两个。通常没有,我只看到了毫秒,但对此不做任何假设。如果您需要通知,请让被中断的系统调用在注意到它被中断后执行此操作。)

将信号传递到已安装的 empty_handler() 函数会导致同一线程中的阻塞系统调用中断。调用将失败,返回一个短计数(对于某些类型的套接字),或返回带有 errno == EINTR-1

如果您使用raise(SIGUSR1),内核可以在进程的线程中选择任何线程来处理信号。 (除了告诉内核它们希望通过 pthread_sigmask()sigprocmask() “阻止”信号的线程,或者它们从创建该线程的线程继承了这样的 block 的线程除外。)无论如何,如果该线程处于阻塞系统调用中,它将被中断(由于信号的传递);如果它正在做其他事情,那么该线程只是“借用”了一段时间,并且确实没有中断的迹象。

<小时/>

情况下此机制很有用。特别是,当使用具有较差/故障超时的外部库时,我将其与超时计时器一起使用(使用 timer_create(CLOCK_MONOTONIC, &event, &timer)timer_settime() 在超时时设置初始触发事件,然后以快速的短间隔(每隔几毫秒)重复)支持访问套接字。即使是一个糟糕的库,在最坏的情况下也不会尝试多次阻塞读取,如果它们都因 EINTR 错误而失败——当然,常见的典型情况是第一个一是强制图书馆立即报告错误。真正让我困扰的是那些极端的情况;我只想发布可靠的代码,不会因为月亮恰好处于错误的相位而崩溃。

关于c - 如何唤醒正在 sleep (3)的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38587464/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com