Планирование потоков C - PullRequest
       20

Планирование потоков C

0 голосов
/ 06 апреля 2010
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #define NUM_THREADS  4
 #define TCOUNT 5
 #define COUNT_LIMIT 13

 int     done = 0;
 int    count = 0;
 int     thread_ids[4] = {0,1,2,3};
 int thread_runtime[4] = {0,5,4,1};
 pthread_mutex_t count_mutex;
 pthread_cond_t count_threshold_cv;

 void *inc_count(void *t)
 {
   int i;
   long my_id = (long)t;
   long run_time = thread_runtime[my_id];
   if (my_id==2 && done==0) {
     for(i=0; i<5 ; i++) {
       if (i==4) {
         done = 1;
       }
       pthread_mutex_lock(&count_mutex);
       count++;

       if (count == COUNT_LIMIT) {
         pthread_cond_signal(&count_threshold_cv);
         printf("inc_count(): thread %ld, count = %d  Threshold reached.\n",
           my_id, count);
       }
       printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count);
       pthread_mutex_unlock(&count_mutex);
     }
   }

   if (my_id==3 && done==1) {
     for(i=0; i< 4 ; i++) {
       if (i==3) {
         done = 2;
       }
       pthread_mutex_lock(&count_mutex);
       count++;

       if (count == COUNT_LIMIT) {
         pthread_cond_signal(&count_threshold_cv);
         printf("inc_count(): thread %ld, count = %d  Threshold reached.\n",
           my_id, count);
       }
       printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count);
       pthread_mutex_unlock(&count_mutex);
     }
   }

   if (my_id==4 && done==2) {
     for(i=0; i<8; i++) {
       pthread_mutex_lock(&count_mutex);
       count++;
       if (count == COUNT_LIMIT) {
         pthread_cond_signal(&count_threshold_cv);
         printf("inc_count(): thread %ld, count = %d  Threshold reached.\n",
           my_id, count);
       }
       printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count);
       pthread_mutex_unlock(&count_mutex);
     }
   }
   pthread_exit(NULL);
 }

 void *watch_count(void *t)
 {
   long my_id = (long)t;

   printf("Starting watch_count(): thread %ld\n", my_id);
   pthread_mutex_lock(&count_mutex);
   if (count<COUNT_LIMIT) {
     pthread_cond_wait(&count_threshold_cv, &count_mutex);
     printf("watch_count(): thread %ld Condition signal received.\n", my_id);
     count += 125;
     printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
   }
   pthread_mutex_unlock(&count_mutex);
   pthread_exit(NULL);
 }

 int main (int argc, char *argv[])
 {
   int i, rc;
   long t1=1, t2=2, t3=3, t4=4;
   pthread_t threads[4];
   pthread_attr_t attr;

   pthread_mutex_init(&count_mutex, NULL);
   pthread_cond_init (&count_threshold_cv, NULL);
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
   pthread_create(&threads[0], &attr, watch_count, (void *)t1);
   pthread_create(&threads[1], &attr, inc_count, (void *)t2);
   pthread_create(&threads[2], &attr, inc_count, (void *)t3);
   pthread_create(&threads[3], &attr, inc_count, (void *)t4);

   for (i=0; i<NUM_THREADS; i++) {
     pthread_join(threads[i], NULL);
   }
   printf ("Main(): Waited on %d  threads. Done.\n", NUM_THREADS);

   pthread_attr_destroy(&attr);
   pthread_mutex_destroy(&count_mutex);
   pthread_cond_destroy(&count_threshold_cv);
   pthread_exit(NULL);
 }

Таким образом, этот код создает 4 потока. Поток 1 отслеживает значение счетчика, а остальные 3 увеличивают значение счетчика. Время выполнения - это количество раз, которое поток будет увеличивать значение счетчика. У меня есть готовое значение, которое позволяет первому потоку увеличивать значение счетчика первым до тех пор, пока его время выполнения не истечет ... так что это как First Come First Serve.

Мой вопрос: есть ли лучший способ реализовать это? Я читал о SCHED_FIFO или SCHED_RR. Я думаю, я не знаю, как внедрить их в этот код или если это может быть

Ответы [ 2 ]

2 голосов
/ 06 апреля 2010

Если я правильно понимаю вопрос, вы пытаетесь создать что-то вроде конвейера, где следующий поток обнаруживает, где предыдущий останавливается. Самым чистым решением в этом случае является использование двоичных семафоров .

Скажем, у вас есть четыре темы. Создайте четыре семафора с начальными значениями {1, 0, 0, 0}. Назначьте семафор для каждого потока, и у каждого потока down свой семафор при запуске и up следующий семафор (по модулю числа потоков) в цепочке. Запустить все потоки - первый немедленно получает свой семафор, выполняет свою работу, другие потоки блокируют свои семафоры. Первый поток завершает работу, up s следующий семафор, таким образом, пробуждая следующий поток, затем возвращается к началу и т. Д. И т. Д.

Я думаю, что классы планирования в реальном времени, о которых вы говорите, не имеют никакого отношения к рассматриваемой проблеме.

Некоторые примечания к вашему коду:

  • переменные, не защищенные блокировками, которые сигнализируют об изменении состояния между потоками (например, done здесь), должны быть volatile, поэтому компилятор не оптимизирует их вне циклов.
  • Вы можете использовать аргумент функции потока для передачи более сложной информации потоку, например, указатель на структуру.
  • Вы всегда хотите вызвать pthread_cond_wait в цикле , где условие цикла проверяет, что вы ожидаете. Это нужно во избежание ложных пробуждений .
  • Вы всегда хотите позвонить pthread_cond_signal либо вне замка, либо в качестве самой последней вещи перед разблокировкой. Это сделано для того, чтобы избежать ненужных циклов пробуждения / сна в ожидающих потоках - они просыпаются, находят мьютекс все еще заблокированным, блокируют (спят) снова.
  • избегайте множества потоков, участвующих в одной и той же блокировке, это приводит к гремящему стаду проблема.
  • всегда проверка возвращаемых значений вызовов pthread.

Надеюсь, это поможет.

1 голос
/ 06 апреля 2010

SCHED_FIFO и SCHED_RR являются классами планирования в реальном времени.Они не для использования в обычном коде.Вы должны быть в состоянии сделать большинство всего, что вам нужно, используя мьютексы pthread.

...