簡體   English   中英

即使使用睡眠,線程也不會放棄CPU時間

[英]Threads not relinquishing CPU time even if using sleep

我正在有多個線程的地方運行此程序。 三個線程為同一父進程生成信號。 有四個處理程序線程,用於處理由信號生成線程生成的信號。 我有一個監視線程,該線程也接收相應的信號和進程。 但是,我有一個情況。 我可以看到信號沒有被平均分配。 我的意思是信號被定向到相同的過程。 我有四個處理程序線程和一個監視線程在等待信號。 因此,任何人都可以接收信號。 我期望它可以均勻分布。 但是,我可以看到,在處理程序線程接收到整個信號突發的時候。 下次所有信號突發都由監視線程處理。 為什么不統一。 在處理程序/監視器線程完成處理一個信號之后,我添加了一個sleep調用。 因此,一旦處理程序/監視程序完成一個信號,它就應該給另一個機會處理下一個信號。 但是,輸出不顯示情況

#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,我就添加了sleep調用,以便將轉彎傳遞到下一個可用線程。 但是,這沒有幫助。 我猜這應該使它統一。 但是,監視器仍然破裂並打印。 即使在監視器中,我已經在完成信號工作后進入睡眠狀態

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

第一個也是最重要的一個是為每個線程分配一個運行時間片。 可以通過信號或IO中斷該時間片,但不是線程將運行直到完成其時間片。 因此,即使您進行了睡眠-如果睡眠時間小於該線程的時間片,它也不會將執行轉移到其他線程。 如果我記得在Windows上,此時間片至少為5毫秒,但通常為40毫秒(盡管我可能輸入的數字有誤)。 在linux上,這個時間片可能會更短,但對於通用linux盒,我認為是相同的。 我曾經使用Sleep(0)放棄Windows上的時間片。 usleep(0)可能執行相同的操作。 因此,您使用睡眠的方式不會做您想要的。 但是,由於您使用的是pthread,因此只需調用pthread_yield即可放棄CPU或sched_yield() ,這應該是更好的做法,但誰知道...

您的測試輸出可能面臨的第二個問題是,實際上您沒有直接的方法來控制在多線程環境中輸出到流的字符的順序。 如果您確實希望輸出正常,則需要實現一個單獨的線程來執行輸出,並使用隊列和某種鎖定機制(臨界區,互斥體)或自由鎖定機制將消息發送給i。

希望這能使您朝正確的方向前進

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM