Переменные условия SHECD_FIFO и Posix - PullRequest
0 голосов
/ 01 февраля 2019

Я использую условные переменные SCHED_FIFO и pthread.

Программа состоит из 3 потоков: «основной» с более высоким приоритетом для процессора 0, «задача_1» также для процессора 0 и «задача_2» ссамый низкий приоритет на процессоре 1.

Для точки зрения переменной условия posix «main» - это производитель, а остальные потоки - «потребители».

Проблема заключается в следующем: после вызова широковещания основной прерывается задачей task_1, которая имеет более низкий приоритет, а затем task_2 также завершает свое выполнение до основной ...

Трасса (всегда) следующая:

[main]   creating task_2
[task_2] lock
[task_2] wait
[main]   creating task_1
[task_1] lock
[task_1] wait
[main]   before lock
[main]   before unlock
[task_1] running
[main]   after unlock
[task_1] unlock
[task_2] running
[main]   finished
[task_2] unlock
using time_ns_t = uint64_t;
constexpr time_ns_t sec_to_us(time_ns_t sec) {
  return sec * 1000000;
}
pthread_mutex_t mutex;
void            mutex_init() {
  pthread_mutexattr_t attr;
  pthread_mutexattr_init(&attr);
  // pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE);
  pthread_mutex_init(&mutex, &attr);
}
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
bool ready = false;
//--------------------------------------------------
uint64_t total_usage(const struct rusage& usage) {
  uint64_t u_sec   = usage.ru_utime.tv_sec;
  uint64_t u_micro = usage.ru_utime.tv_usec;
  uint64_t s_sec   = usage.ru_stime.tv_sec;
  uint64_t s_micro = usage.ru_stime.tv_usec;    
  return (u_sec + s_sec) * 1000000 + (u_micro + s_micro);
}

uint64_t burn_cpu(uint64_t microsec) {
  struct rusage usage;
  getrusage(RUSAGE_THREAD, &usage);
  uint64_t init     = total_usage(usage);
  uint64_t duration = 0;
  while (duration < microsec) {
    getrusage(RUSAGE_THREAD, &usage);
    duration = total_usage(usage) - init;
  }
  return duration;
}
//--------------------------------------------------
int set_cpu(int cpu) {
  cpu_set_t set;
  CPU_ZERO(&set);
  CPU_SET(cpu, &set);
  return sched_setaffinity(0, sizeof(cpu_set_t), &set);
}
int set_rt_priority(int priority) {
  struct sched_param sp;
  sp.sched_priority = priority;
  return sched_setscheduler(0, SCHED_FIFO, &sp);
}
//--------------------------------------------------
void* thread_start_1(void* data) {
  set_cpu(0);
  set_rt_priority(20);
  std::cout << "[task_1] lock\n";
  pthread_mutex_lock(&mutex);
  while (!ready) {
    std::cout << "[task_1] wait\n";
    pthread_cond_wait(&cond, &mutex);
  }
  std::cout << "[task_1] running\n";
  burn_cpu(sec_to_us(1));
  pthread_mutex_unlock(&mutex);
  std::cout << "[task_1] unlock\n";
  return nullptr;
}

void* thread_start_2(void* data) {
  set_cpu(1);
  set_rt_priority(10);
  std::cout << "[task_2] lock\n";
  pthread_mutex_lock(&mutex);
  while (!ready) {
    std::cout << "[task_2] wait\n";
    pthread_cond_wait(&cond, &mutex);
  }
  std::cout << "[task_2] running\n";
  burn_cpu(sec_to_us(1));
  pthread_mutex_unlock(&mutex);
  std::cout << "[task_2] unlock\n";
  return nullptr;
}

int main(int argc, char* argv[]) {
  pthread_t id_1, id_2;

  set_cpu(0);
  set_rt_priority(50);

  burn_cpu(sec_to_us(1));

  std::cout << "[main]   creating task_2\n";
  pthread_create(&id_2, nullptr, thread_start_2, nullptr);
  burn_cpu(sec_to_us(1));

  std::cout << "[main]   creating task_1\n";
  pthread_create(&id_1, nullptr, thread_start_1, nullptr);
  burn_cpu(sec_to_us(1));

  std::cout << "[main]   before lock\n";
  pthread_mutex_lock(&mutex);
  ready = true;
  pthread_cond_broadcast(&cond);
  std::cout << "[main]   before unlock\n";
  pthread_mutex_unlock(&mutex);
  std::cout << "[main]   after unlock\n";

  burn_cpu(sec_to_us(1));
  std::cout << "[main]   finished\n";

  pthread_join(id_1, nullptr);
  pthread_join(id_2, nullptr);

  return 0;
}
...