2012-09-30 56 views
1

我正在運行此程序,我有多個線程。三個線程正在爲同一父進程生成信號。有四個處理線程用於處理由信號生成線程生成的信號。我有一個監視線程,它也接收信號和進程。但是,我有一個情況。我可以看到信號並不是平等分配的。我的意思是信號指向同一個過程。我有四個處理程序線程和一個監視線程等待信號。所以他們中的任何人都可以收到信號。我期待它被統一分發。但是,我可以看到,處理器線程接收到一整串信號。下一次整個信號突發由監視器線程處理。爲什麼它不統一。處理程序/監視器線程完成處理一個信號後,我添加了一個睡眠調用。所以只要處理器/監視器完成一個信號,它就應該有另一個機會來處理下一個信號。但是,輸出不顯示的情況下即使使用睡眠也不放棄CPU時間的線程

#include <pthread.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <iostream> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <signal.h> 
#include <cstdio> 
#include <stdlib.h> 

#define NUM_SENDER_PROCESSES 3 
#define NUM_HANDLER_PROCESSES 4 
#define NUM_SIGNAL_REPORT 10 
#define MAX_SIGNAL_COUNT 100000 


using namespace std; 

volatile int usrsig1_handler_count = 0; 
int usrsig2_handler_count = 0; 
int usrsig1_sender_count = 0; 
int usrsig2_sender_count = 0; 
int monitor_count = 0; 
int usrsig1_monitor_count = 0; 
int usrsig2_monitor_count = 0; 
double time_1[10]; 
double time_2[10]; 
int lock_1 = 0; 
int lock_2 = 0; 
int lock_3 = 0; 
int lock_4 = 0; 
int lock_5 = 0; 


double timestamp() { 
    struct timeval tp; 
    gettimeofday(&tp, NULL); 
    return (double)tp.tv_sec + tp.tv_usec/1000000.; 
} 

void sleepMs(double seconds) { 
    usleep((unsigned int)(seconds*1000000)); 
} 

void *senderfunc(void *parm) { 
    srand(time(0)); 
    while(true) { 
    int signal_id = rand()%2 + 1; 
    if(signal_id == 1) { 
     while(__sync_lock_test_and_set(&lock_3,1) != 0) { 
     } 
     usrsig1_sender_count++; 
     lock_3 = 0; 
     kill(getpid(), SIGUSR1); 
    } else { 
     while(__sync_lock_test_and_set(&lock_4,1) != 0) { 
     } 
     usrsig2_sender_count++; 
     lock_4 = 0; 
     kill(getpid(), SIGUSR2); 
    } 


    int r = rand()%10 + 1; 
    double s = (double)r/100; 
    sleepMs(s); 
    } 
} 

void *handlerfunc(void *parm) 
{ 
    int *index = (int *)parm; 
    sigset_t set; 
    sigemptyset(&set); 
    //cout << (*index) << endl; 
    if((*index) % 2 == 0) { 
    sigaddset(&set, SIGUSR1); 
    } else { 
    sigaddset(&set, SIGUSR2); 
    } 


    int sig; 

    while(true) { 
    sigwait(&set, &sig); 
    //cout << "Handler" << endl; 
    if (sig == SIGUSR1) { 
     while(__sync_lock_test_and_set(&lock_1,1) != 0) { 
     } 
     usrsig1_handler_count++;   
     lock_1 = 0; 
    } else if(sig == SIGUSR2) { 
     while(__sync_lock_test_and_set(&lock_2,1) != 0) { 
     } 
     usrsig2_handler_count++; 
     lock_2 = 0; 
    } 

    sleepMs(0.0001); 
    } 

} 

void *monitorfunc(void *parm) { 

    sigset_t set; 
    sigemptyset(&set); 

    sigaddset(&set, SIGUSR1); 
    sigaddset(&set, SIGUSR2); 

    int sig; 

    while(true) { 
    sigwait(&set, &sig); 
    //cout << "Monitor" << endl; 
    if(sig == SIGUSR1) { 
     time_1[usrsig1_monitor_count] = timestamp(); 
     usrsig1_monitor_count++; 
    } else if(sig == SIGUSR2) { 
     time_2[usrsig2_monitor_count] = timestamp(); 
     usrsig2_monitor_count++; 
    } 
    monitor_count++; 
    //cout << monitor_count << endl; 

    if(monitor_count == NUM_SIGNAL_REPORT) { 
     double difference_1 = 0; 
     double difference_2 = 0; 
     if(usrsig1_monitor_count > 1) { 
     for(int i=0; i<usrsig1_monitor_count-1; i++) { 
      difference_1 = difference_1 + time_1[i+1] - time_1[i]; 
     } 
     cout << "Interval SIGUSR1 = " << difference_1/(usrsig1_monitor_count-1)<< endl; 
     } 

     if(usrsig2_monitor_count > 1) { 
     for(int i=0; i<usrsig2_monitor_count-1; i++) { 
      difference_2 = difference_2 + time_2[i+1] - time_2[i]; 
     } 
     cout << "Interval SIGUSR2 = " << difference_2/(usrsig2_monitor_count-1) << endl; 
     } 
     cout << "Count SIGUSR1 = " << usrsig1_sender_count << endl; 
     cout << "Count SIGUSR2 = " << usrsig2_sender_count << endl; 
     monitor_count = 0; 
     usrsig1_monitor_count = 0; 
     usrsig2_monitor_count = 0; 
    } 

    sleepMs(0.001); 

    } 
} 

int main(int argc, char **argv) 
{ 
    if(argc != 2) { 
    cout << "Required parameters missing. " << endl; 
    cout << "Option 1 = 1 which means run for 30 seconds" << endl; 
    cout << "Option 2 = 2 which means run until 100000 signals" << endl; 
    exit(0); 
    } 

    int option = atoi(argv[1]); 
    int i; 

    pthread_t handlers[NUM_HANDLER_PROCESSES]; 
    pthread_t generators[NUM_SENDER_PROCESSES]; 
    pthread_t monitor; 

    sigset_t set; 
    sigset_t oldset; 
    sigemptyset(&oldset); 
    sigemptyset(&set); 
    sigaddset(&set, SIGUSR1); 
    sigaddset(&set, SIGUSR2); 

    pthread_sigmask(SIG_BLOCK, &set, &oldset); 


    int handler_mask[4] = {0,1,2,3}; 
    //Initializing the handler threads 
    for(i=0; i<NUM_HANDLER_PROCESSES; i++) { 
    pthread_create(&handlers[i], NULL, handlerfunc, (void *)&handler_mask[i]); 
    } 

    pthread_create(&monitor, NULL, monitorfunc, NULL); 

    sleep(5); 

    for(i=0; i<NUM_SENDER_PROCESSES; i++) { 
    pthread_create(&generators[i], NULL, senderfunc, NULL); 
    } 

    if(option == 1) { 
    cout << "Option 1 " << endl; 
    //sleep(30); 
    while(true){ 

    } 
    exit(0); 
    } else { 
    while(true) { 
     if((usrsig1_handler_count + usrsig2_handler_count) >= MAX_SIGNAL_COUNT) { 
     cout << "Count SIGUSR1 = " << usrsig1_handler_count << endl; 
     cout << "Count SIGUSR2 = " << usrsig2_handler_count << endl; 
     exit(0); 
     } else { 
     pthread_yield(); 
     } 
    } 
    } 
} 

這裏是我的輸出

HandlerHandler 

Handler 
Handler 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Monitor 
Handler 
Handler 
Handler 
Handler 
Handler 
Handler 
Handler 
Handler 
Handler 
Handler 

你可以看到顯示器的突發,隨後處理的爆裂。但是,在代碼中,一旦處理程序/監視器處理了一個信號並進入sigwait,我就添加了一個睡眠調用,以便將該轉換傳遞給下一個可用線程。但是,這沒有幫助。我猜這應該是統一的。但是,監視器仍然會爆炸並打印。即使在監視器中,當它已完成其信號作業後,它已經進入睡眠狀態

+0

@ K-ballo。我沒有明白。當處理器/顯示器從sigwait中喚醒時,我只是在打印。由於我已經使用了睡眠,所以他們應該輪流醒來。我的意思是我在顯示器線程上使用了sigwait,它處理一個信號然後睡覺。與此同時,處理線程獲得CPU時間,從sigwait中喚醒並處理信號並進入睡眠狀態。所以他們應該輪流是不是? – user34790

+0

有什麼辦法可以看到,即使我使用睡眠爲什麼同一個線程有機會使用sigwait解鎖信號並處理它? – user34790

+0

你的問題是什麼?你想知道線程時間爲什麼沒有統一分佈? – user1708860

回答

1

代碼有兩個不同的問題,可以讓您看到結果。

第一個也是最重要的是每個線程都分配了一個時間片來運行。這個時間片可以被信號或IO中斷,而不是一個線程將運行直到它完成時間片。所以,即使你進行了睡眠 - 如果睡眠時間小於該線程的時間片,它也不會將執行轉移到其他線程。如果我記得在Windows上這個時間片至少是5ms,但通常是40ms(儘管我可能有錯誤的號碼)。在Linux上,這個時間片可能會更短,但對於通用Linux盒子,我認爲它是一樣的。我曾經使用Sleep(0)來放棄Windows上的時間片。 usleep(0)可能會做同樣的事情。所以你使用睡眠的方式不會做你想做的。但是,由於您使用的並行線程只是叫pthread_yield放棄這應該是更好的做法,但誰知道CPU或SCHED_YIELD() ...

你可以跟你的測試輸出面臨的第二個問題是您實際上沒有直接的方法來控制在多線程環境中輸出到流的字符順序。如果你真的想要輸出爲了你需要實現一個單獨的線程做輸出,並使用隊列和一些鎖定機制(臨界區,互斥鎖)或自由鎖定機制將消息發送給i。

希望這個得到你的正確方向