2016-07-26 187 views
-2

我想在我的主線程的另一個線程中打破sleep (3)。要做到這一點,我想在使用raise (sig)並在打破系統調用後繼續執行代碼。如何喚醒睡眠(3)ing線程

那麼,我應該使用哪個信號來導致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); 
} 
+3

經典[XY問題](http://xyproblem.info)。你真的想做什麼? –

+0

我附加的程序應該解釋一下,我嘗試通過raise() – bzzzz7

+1

生成EINTR我重新解釋了你的問題,所以它表達了你想解決的實際問題。 – a3f

回答

-1

當您按下CTR + C,操作系統發送一個信號process.This將發送SIGINT signal.The SIGINT(「計劃中斷」 )是終止信號之一.SIGINT是一個特殊信號,因爲它可以由程序處理(捕獲)。 SIGINT的默認操作是程序終止。要更改信號的默認操作,您必須註冊要捕獲的信號。要註冊在C程序(至少在POSIX系統)的信號有被包括在C兩個功能

  1. signal(int signum, sighandler_t handler);
  2. sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

這些功能所需要的報頭signal.h中碼。

例如:

#include ... 
#include ... 
#include<signal.h> 
void handler(int sig){ 
cout << "Interrupt signal (" << signum << ") received.\n"; 
} 
int main() 
{ 
    //registering signal by signal function 
    signal(SIGINIT,handler); 

    //your code 

while(++i){ 
     cout << "Going to sleep...." << endl; 
     if(i == 3){ 
      raise(SIGINT); 
     } 
     sleep(1); 
    } 
//your code 

    return 0; 
} 
+0

我不想使用處理程序。我想要導致在diffrren線程中斷系統調用的中斷並檢查它是否如下所示:if(errno == EINTR){..restart the system-call ... } – bzzzz7

+0

你可以使用SIGABRT信號,然後 –

+0

沒有工作,我得到了「Aborted(核心傾棄)」我附加了我的程序,我希望現在我的問題會更清楚。 – bzzzz7

1

您可以讓其他線程blocked on a condition variable with a timeout

#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/time.h> 
#include <errno.h> 

pthread_cond_t  cond = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER; 
int interrupted; 

#define WAIT_TIME_SECONDS 20 
void *event_loop (void *arg) 
{ 
    struct timespec ts; 
    struct timeval tv; 

again: 
    gettimeofday(&tv, NULL); 

    ts.tv_sec = tv.tv_sec; 
    ts.tv_nsec = tv.tv_usec * 1000; 
    ts.tv_sec += WAIT_TIME_SECONDS; 

    pthread_mutex_lock(&mutex); 
    while (!interrupted) { 
     int rc = pthread_cond_timedwait(&cond, &mutex, &ts); 
     if (rc == ETIMEDOUT) { 
      printf("Timed out!\n"); 
      pthread_mutex_unlock(&mutex); 
      goto again; 
     } 
    } 
    printf("Woke up!\n"); 
    interrupted = 0; 
    pthread_mutex_unlock(&mutex); 
    goto again; 
} 

int main(void) { 
    pthread_t thread; 
    pthread_create(&thread, NULL, event_loop, NULL); 
    while (getchar() != EOF) { 
     pthread_mutex_lock(&mutex); 
     interrupted = 1; 
     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

如果你想擁有由像SIGINT信號引發的信號,無論是在一個專門的線程中使用sigwait或使用Semaphores。條件變量不是異步信號安全的。

2

這不是一箇中斷阻塞系統調用的信號;它是傳遞的信號到註冊的處理程序(沒有安裝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; 
    } 

。 (信號處理程序總是分配給一個進程中的所有線程,不能爲一個線程設置一個處理程序,爲另一個線程設置另一個處理程序,您可以在已安裝的處理程序中檢查當前線程標識,並根據它進行處理。並不需要在創建線程之前進行安裝;它只是在創建線程之前安裝的處理程序更容易維護,並留下少很多比賽窗)

比方說,你有pthread_t somethread;含用於線程標識符somethread。一個處於阻塞系統調用中的線程。

如果調用,從任何線程,

pthread_kill(somethread, SIGUSR1); 

SIGUSR1信號被髮送給該線程。 (請注意,pthread_kill()呼叫將立即返回,並且您不得假設該信號已在此時傳送,如果您還想要傳送通知,則需要使用其他一些機制。此外,信號首先會送到;攔截系統調用在傳送後才中斷,如果系統負載較重,兩者之間可能會有可測量的延遲。通常沒有,我只看到毫秒,但沒有對此做任何假設。如果需要通知,請在中斷的系統調用通知它被中斷後執行。)

將信號傳遞到安裝的empty_handler()函數會導致同一線程中的阻塞系統調用中斷。該呼叫將失敗,返回一個短計數(對於某些類型的套接字),或者返回與errno == EINTR

如果您改爲使用raise(SIGUSR1),內核可以在進程的線程中選擇任意線程來處理信號。 (除了已通知內核的線程,他們希望通過pthread_sigmask()sigprocmask()「阻止」信號,或者它們已從創建該線程的線程繼承了此類塊)。 無論如何,如果該線程處於阻塞系統調用,它會被中斷(由於信號的傳遞);如果它正在做別的事情,這個線程只是「借用」了一段時間,而且沒有任何中斷的跡象。


案件哪裏這個機制是非常有用的。特別是,我使用超時定時器(使用timer_create(CLOCK_MONOTONIC, &event, &timer)timer_settime()在超時設置初始觸發事件,然後以快速的短間隔,每幾毫秒重複一次),這是因爲在使用支持訪問套接字的差/超時超時的外部庫時。即使是一個糟糕的圖書館,在最壞的情況下,如果它們全都失敗,也不會嘗試阻止閱讀,最多幾次都會失敗 - 當然,通常情況下,第一個迫使圖書館報告立即出錯。這是真正困擾我的角落案件;我只想發佈一些健壯的代碼,因爲月亮恰好處於錯誤的階段,所以不會輕易發生。