2014-05-13 35 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$