8

複数のスレッドがあるこのプログラムを実行しています。3 つのスレッドが同じ親プロセスのシグナルを生成しています。シグナル生成スレッドによって生成されたシグナルを処理するための 4 つのハンドラ スレッドがあります。信号を受信し、それに応じて処理する監視スレッドもあります。しかし、私には状況があります。信号が均等に分割されていないことがわかります。つまり、信号は同じプロセスに向けられています。シグナルを待っている 4 つのハンドラー スレッドと 1 つの監視スレッドがあります。そのため、誰でも信号を受信できます。一様に配布されると思っていました。ただし、シグナルのバースト全体がハンドラー スレッドによって受信されることがわかりました。次回、信号のバースト全体がモニタースレッドによって処理されます。どうせ均一じゃない。ハンドラー/モニター スレッドが 1 つのシグナルの処理を完了した後、スリープ コールを追加しました。したがって、ハンドラー/モニターが 1 つのシグナルを完了するとすぐに、次のシグナルを処理する別の機会を与える必要があります。ただし、出力はケースを示していません

#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
... whole bunch of Monitor messages
Monitor
Monitor
Handler
Handler
... whole bunch of Handler messages
Handler
Handler

モニターのバーストに続いてハンドラーのバーストが見られます。ただし、ハンドラー/モニターがシグナルを処理して sigwait に移行したコードでは、次の使用可能なスレッドにターンが渡されるようにスリープ呼び出しを追加しました。ただし、これは役に立ちません。これで均一化できたはずです。ただし、それでもモニターはバーストして印刷されます。モニターでは、信号の仕事が終わった後にスリープ状態にしましたが

4

2 に答える 2

3

どのOSを使用していますか?これを確実に行うには、リアルタイム オペレーティング システム (RTOS) が必要です。On Time RTOS-32と呼ばれる非常に小さな RTOS を使用して、ロボット コントローラーを駆動することで、良い結果が得られました。遅延が保証されたタイム スライスを実行することも、協調スケジューリングを選択することもできます。Win API のサブセット用に設定されたウィンドウ エミュレーションがあります。IDE として Visual Studio/VC++ を使用しました。現在利用可能な RTOS のかなりの種類があるかもしれません。それはほぼ10年前のことです。RTOS と「リアルタイム オペレーティング システム」の Google。

別の方法としては、高速な専用マシンで十分な場合がありますが、独自の「OS 内の OS」を記述して、「手動で」スレッドをスケジュールすることです。スレッドが割り当てを待つ方法を変更する必要があります。

暗闇で撮影しています。スレッド間で負荷を分散する必要があるのはなぜですか? タスクは何ですか?予算は?特定のハードウェアで実行する必要がありますか? 特定のOSで?もしそうならどれ?それがポンコツになるとどうなりますか?誰かが悪い言葉をつぶやいて昼食に行くか、宇宙探査機の鼻が太陽に飛び込みますか?

于 2012-10-05T19:05:51.930 に答える
1

OS は、複数のスレッド間で JOB を分散する必要があることを認識していないため、OS は使用可能な最初のスレッドを最も高い優先度で実行し、現在のスレッドが何か (ユーザー入力、ディスクまたはネットワーク アクティビティなど) を待機するまで、そのスレッドを実行し続けます。優先度の高い別のスレッドが使用可能になります。-パフォーマンスを向上させ、コンテキストの切り替えが多すぎるのを避けるために、OSは同じスレッドでリクエストをディスパッチしようとします(必要とは反対です)。

たとえば、MonitorThread の実行がスケジュールされていて、その呼び出しsigwaitが満たされているとします。そのアクションが完了すると (このスレッドは CPU を所有しているため、OS は他のスレッドをスケジュールする方法がありません)、そのアクションが完了すると (その間に) 呼び出しますsigwait。そこに保留中のシグナルがある場合、OS はそのシグナルを取得し、再びループを通過します。このスレッドは、保留中のシグナルがなくなるまでこのプロセスを実行し、sigwaitその操作をブロックし、次回は他のスケジュールされたスレッドで操作が繰り返されます。

シグナルを均等にディスパッチするには、独自のメカニズムを実装する必要があります(OSにはこのためのメカニズムがないため)。スレッドごとに作成し、condition_variable最初に各スレッドを強制的に待機させてcondition_variableから呼び出すことができます。sigwait実行が完了するとcondition_variable、次のスレッドが設定され、操作はそのままになります!.

于 2012-10-03T07:34:26.603 に答える