使线程获得相同的时间

use*_*790 8 c multithreading operating-system

我正在运行这个程序,我有多个线程.三个线程正在为同一父进程生成信号.有四个处理程序线程用于处理由信号生成线程生成的信号.我有一个监控线程,它也接收信号和进程.但是,我有一个情况.我可以看到信号没有平分.我的意思是信号指向同一个过程.我有四个处理程序线程和一个等待信号的监视线程.所以他们中的任何人都可以收到信号.我期待它能够统一分发.但是,我可以看到处理器线程接收到整个信号突发.下一次整个信号突发由监控线程处理.为什么不均匀.在处理程序/监视器线程完成处理一个信号后,我添加了一个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();
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的输出

HandlerHandler

Handler
Handler
Monitor
Monitor
... whole bunch of Monitor messages
Monitor
Monitor
Handler
Handler
... whole bunch of Handler messages
Handler
Handler
Run Code Online (Sandbox Code Playgroud)

您可以看到监视器的突发,然后是处理程序的爆发.但是,在代码中,一旦处理程序/监视器处理信号并进入sigwait,我就添加了一个sleep调用,以便将转向传递给下一个可用的线程.但是,这没有帮助.我猜这应该是统一的.然而,仍然监视器爆裂和打印.即使在监视器中,我已经完成了信号工作后的睡眠状态

Big*_*oss 1

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

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

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