2014-05-13 37 views
3

中断阻塞调用简单的代码下面举例说明我在醒来是在司机的呼叫阻塞线程的问题。我没有驱动程序源代码,但是如果驱动程序阻塞的物理设备发生电源中断,则需要唤醒线程才能关闭进程。从并行线程

实施例(见下面的代码):

main()设置一个信号处理程序SIGINT,启动一个子线程,然后进入无限循环的地方反复休眠模式唤醒,并打印出时醒来。子线程执行相同的操作,但每次唤醒时,它也会向该进程发送一个SIGINTsleep()被用作一个简单的阻塞呼叫。

运行代码显示了以下行为:

  • 每次孩子线程被唤醒,它打印的“当”的消息(当它醒来的时候)。然后信号处理程序报告它收到了SIGINT
  • 每次“主”唤醒时,它打印的“当”的消息。

如下:

main: 0.127 

Child: 0.127 

SignalHandler: signum = 2 

Child: 5.127 

SignalHandler: signum = 2 

main: 7.127 

Child: 10.127 

SignalHandler: signum = 2 

main: 14.127 

Child: 15.128 

SignalHandler: signum = 2 

Child: 20.128 

SignalHandler: signum = 2 

main: 21.127 

. 
. 
. 

我预计,通过该过程中收到的SIGINT的结果,main()会打破它的阻止呼叫sleep()的。这将被视为main()打印它'时'的消息。事实上,这正是我看看,如果我从壳型按Ctrl-CSIGINT)的行为。您可以在下面看到两个Ctrl-C中断。每一次,main()确实摆脱它的阻止呼叫sleep()

main: 0.417 

child: 0.417 

SignalHandler: signum = 2 

child: 5.417 

SignalHandler: signum = 2 

^C 

SignalHandler: signum = 2 

main: 6.664 

child: 10.417 

SignalHandler: signum = 2 

main: 13.664 

child: 15.418 

SignalHandler: signum = 2 

^C 

SignalHandler: signum = 2 

main: 16.680 

child: 20.418 

SignalHandler: signum = 2 

main: 23.680 

child: 25.418 

SignalHandler: signum = 2 

-----------守则---------------

// Compile using: 
// g++ Test.cpp -o Test -g -lpthread -lrt 

#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <signal.h> 
#include <time.h> 

void When(const char *who) { 
    timespec sTimespec; 
    static long startSecond = -1; 

    clock_gettime(CLOCK_MONOTONIC, &sTimespec); 

    if (startSecond == -1) 
    startSecond = sTimespec.tv_sec; 

    sTimespec.tv_sec -= startSecond; 
    sTimespec.tv_nsec /= 1e+6; // only show milliseconds 
    printf("%s: %ld.%03ld\n", who, sTimespec.tv_sec, sTimespec.tv_nsec); 
} 

void SignalHandler(int signum) { 
    printf("SignalHandler: signum = %d\n", signum); 
} 

void *Child(void *pContext) { 
    char temp[256]; 

    for (;;) { 
    When("Child"); 
    kill(getpid(), SIGINT); 
    sleep(5); 
    } 
} 

int main(int argc, char **argv) { 
    pthread_t childThread; 

    signal(SIGINT, SignalHandler); 
    pthread_create(&childThread, NULL, Child, NULL); 

    for (;;) { 
    When("main"); 
    sleep(7); 
    } 

    return 0; 
} 

所以好像当一个进程发送SIGINT到自身时,信号被交付(见第一个结果),但阻塞调用不被中断。从外部进程发送SIGINT将传递信号,并阻止呼叫被中断。

我试过

其他的事情:

raise(SIGINT); 

pthread_kill(mainThreadId, SIGINT); // where mainThreadId is resolved to pthread_self() from within 'main' 

sprintf(temp, “kill -2 %d”, getpid()); system(temp); 

我写了一个独立的程序(xkill)采用一个PID作为参数,并发送SIGINT到PID。

然后:

sprintf(temp, “xkill %d”, getpid()); system(temp); 

注:我可以运行从shell这个程序,并获得良好的/预期的行为。

在我看来,没有任何儿童(线程或进程)可以中断其父阻塞调用,即使它可以提供一个信号。

一个你能提供一些线索在这种情况呢?

对于我的真实代码,我需要以编程方式打破阻塞驱动程序调用,所以我可以干净地关闭。在我的真实代码中,子线程是设备运行状况监视器。

+0

只是安排事情,所以该线程将只做无害的事情,当它爆发的功能,或许通过检查从取消标志的功能和设置返回取消标志。那么你不必关心线程是否脱离函数。 –

+1

进程中的任何线程都可以用来传递信号;如果信号传送到同一个线程,阻塞呼叫只会中断。 (即使信号处理程序有一个空的主体。)因此,您需要阻止除希望中断的那个线程(即阻塞呼叫)之外的所有线程中的信号,或者可以使用信号处理程序来转发信号到期望的线程(除非已经被期望的线程捕获)。 Paul Griffiths已经回答了后者的一个很好的例子,尽管我猜想一个更简单/更直接的例子是可能的。 –

回答

0

随着一些小的修改,似乎工作,你的愿望在我结束(Debian的Linux的 - 如果我拿出clock_gettime()东西,它在Mac OS X同样的方式,太)与pthread_kill()

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <stdbool.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <time.h> 

void When(const char *who) { 
    struct timespec sTimespec; 
    static long startSecond = -1; 

    clock_gettime(CLOCK_MONOTONIC, &sTimespec); 

    if (startSecond == -1) { 
     startSecond = sTimespec.tv_sec; 
    } 

    sTimespec.tv_sec -= startSecond; 
    sTimespec.tv_nsec /= 1e+6; // only show milliseconds 
    printf("%s: %ld.%03ld\n", who, sTimespec.tv_sec, sTimespec.tv_nsec); 
} 

void SignalHandler(int signum) { 
    printf("SignalHandler: signum = %d\n", signum); 
} 

void *Child(void *pContext) { 
    pthread_t * main_tid = pContext; 

    while (true) { 
     When("Child"); 
     pthread_kill(*main_tid, SIGINT); 
     sleep(5); 
    } 
} 

int main(void) { 
    pthread_t childThread; 

    struct sigaction sa; 
    sa.sa_handler = SignalHandler; 
    sa.sa_flags = 0; 
    sigemptyset(&sa.sa_mask); 
    if (sigaction(SIGINT, &sa, NULL) == -1) { 
     perror("thread: couldn't set SIGINT handler"); 
     exit(EXIT_FAILURE); 
    }; 

    pthread_t own_tid = pthread_self(); 
    pthread_create(&childThread, NULL, Child, &own_tid); 

    while (true) { 
     When("main"); 
     sleep(7); 
    } 

    return EXIT_SUCCESS; 
} 

和输出:

[email protected]:~/src/c/scratch$ gcc -o thread thread.c -pthread -std=c99 -Wall -Wextra -pedantic -lpthread -lrt 
[email protected]:~/src/c/scratch$ ./thread 
main: 0.464 
Child: 0.464 
SignalHandler: signum = 2 
main: 0.464 
Child: 5.464 
SignalHandler: signum = 2 
main: 5.464 
Child: 10.464 
SignalHandler: signum = 2 
main: 10.464 
Child: 15.464 
SignalHandler: signum = 2 
main: 15.465 
^Z 
[1]+ Stopped     ./thread 
[email protected]:~/src/c/scratch$ kill %1 

[1]+ Stopped     ./thread 
[email protected]:~/src/c/scratch$