8

我正在运行这个程序,我有多个线程。三个线程正在为同一个父进程生成信号。有四个处理线程用于处理由信号生成线程生成的信号。我有一个监控线程,它也接收相应的信号和进程。不过,我有一个情况。我可以看到信号分配不均。我的意思是信号被定向到相同的过程。我有四个处理程序线程和一个监视线程等待信号。所以他们中的任何一个人都可以接收到信号。我期待它均匀分布。但是,我可以看到处理程序线程有时会接收到整个信号突发。下一次整个信号突发由监视器线程处理。为什么不统一。在处理程序/监视器线程完成处理一个信号后,我添加了一个睡眠调用。因此,一旦处理程序/监视器完成一个信号,它就应该给另一个机会来处理下一个信号。但是,输出没有显示这种情况

#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

您使用的是什么操作系统?您需要一个实时操作系统 (RTOS) 来可靠地执行此操作。我使用名为On Time RTOS-32的非常小的 RTOS来驱动机器人控制器,取得了很好的效果。它可以在保证延迟的情况下进行时间切片,或者您可以选择进行协作调度。它为 Win API 的子集设置了 Window 仿真。我们使用 Visual Studio/VC++ 作为 IDE。现在可能有相当多的 RTOS 可用。那是差不多 10 年前的事了。Google for RTOS 和“实时操作系统”。

另一种方法(在快速、专用的机器上可能已经足够好)是编写自己的“操作系统中的操作系统”来“手动”调度线程。您将不得不更改线程等待分配的方式。

我在黑暗中拍摄。为什么需要平衡线程之间的负载?任务是什么?预算是多少?它必须在特定硬件上运行吗?在特定的操作系统上?如果有,是哪个?如果它突然发生了怎么办?有人咕哝了一句脏话去吃午饭,还是太空探测器的鼻子潜入太阳?

于 2012-10-05T19:05:51.930 回答
1

操作系统不知道您要在多个线程之间分配作业,因此操作系统以最高优先级运行第一个可用线程,它继续运行该线程直到当前线程等待某些东西(用户输入、磁盘或网络活动或...)或另一个具有更高优先级的线程变得可用。- 为了提高性能并避免过多的上下文切换,操作系统尝试在同一线程上调度请求(与您的需要相反)。

例如,考虑 MonitorThread 计划运行并且它的调用sigwait得到满足,现在它执行它的操作(虽然这个线程拥有 CPU,操作系统没有办法调度其他线程),当它的操作完成(while 结束)它调用sigwait时,如果有那里有任何挂起的信号,操作系统将接收该信号并再次通过循环,该线程将执行此过程,直到没有更多的挂起信号并sigwait阻止其操作,并且下次该操作将与其他预定线程重复。

现在为了平等地发送信号,我必须实现自己的机制(因为操作系统没有这种机制)。我可以condition_variable为每个线程创建一个并强制他们每个人首先等待自己的condition_variable然后调用sigwait,完成执行后它将设置condition_variable下一个线程并且操作按原样进行!。

于 2012-10-03T07:34:26.603 回答