клон системного вызова и взаимное исключение - PullRequest
0 голосов
/ 24 марта 2011

Я пытаюсь попрактиковаться с клоном syscall и небольшим примером увеличения счетчика, используемого двумя потоками.Код выглядит следующим образом:

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>

#include "error.h"

/*------------------------- Mutual exclusion ------------------------------*/

void EnterCZ()

{
   if (sched_setscheduler(getpid(), SCHED_FIFO, &(struct sched_param) { .sched_priority = 1 }) == -1)
      SysError("EntrarZC:sched_setscheduler");
}

void ExitCZ()
{
   if (sched_setscheduler(getpid(), SCHED_OTHER, &(struct sched_param) { .sched_priority = 0 }) == -1)
      SysError("SalirZC:sched_setscheduler");
}

/*-------------------------------------------------------------------------*/

#define STACK_SIZE 65536
#define N 100000

int main(int argc, char *argv[])
{
   int n = 0;
   char *stack;

   int Child(void *args) {
      int i, temp;

      for (i = 0; i < N; i++) {
         EnterCZ();
         temp = n;
         temp++;
         n = temp;
         ExitCZ();
      }
      return 0;
   }

   printf("initial n = %d\n", n);

   if ((stack = malloc(STACK_SIZE)) == NULL)
      RTError("main:malloc");
   if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
      SysError("main:clone");
   if ((stack = malloc(STACK_SIZE)) == NULL)
      RTError("main:malloc");
   if (clone(Child, stack + STACK_SIZE, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, NULL) == -1)
      SysError("main:clone");

   while (wait(NULL) != -1) ;

   printf("final n = %d\n", n);

   return 0;
}

результат выполнения:

initial n = 0
final n = 199999

должен быть 200000, поэтому взаимное исключение посредством повышения приоритета не удается, почему?

Ответы [ 4 ]

1 голос
/ 25 марта 2011

Здесь есть несколько неправильных вещей:

  • Несколько процессов SCHED_FIFO могут выполняться одновременно на нескольких процессорах.
  • Процессы SCHED_FIFO могут / будут убиты, если они превысят RLIMIT_RTTIME soft / hardlimit.
  • Ничто не мешает переупорядочению команд компилятором.
  • Ничто не мешает переупорядочению команд процессором.
0 голосов
/ 25 марта 2011

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

Как указывал ninjalj, код не работает, если «несколько процессов SCHED_FIFO могут работать одновременно на нескольких процессорах»

Решение для обеспечения работоспособности этого кода - просто запустить исполняемый файл только на одном процессоре:

... $ taskset -c 0 puerta-clone

хорошо работает, с уважением

0 голосов
/ 25 марта 2011

Системный вызов clone() (особенно флаг CLONE_VM) не предназначен для непосредственного использования программистами приложений, создающими потоки. Это низкоуровневый интерфейс, предназначенный для авторов библиотек, создающих полную реализацию потоков. Аналогично, примитивы синхронизации для этих потоков могут быть построены поверх низкоуровневого системного вызова futex(), но опять-таки это не предназначено для непосредственного использования программистами приложений.

Вместо этого вы должны использовать pthreads. Под pthreads используйте pthread_create() вместо clone(); pthread_join() вместо wait(); и pthread_mutex_lock() / pthread_mutex_unlock() для защиты критических секций. Версия вашей программы в pthreads будет выглядеть так:

#include <stdio.h>
#include <pthread.h>

#include "error.h"

/*-------------------------------------------------------------------------*/

#define N 100000

int main(int argc, char *argv[])
{
   int n = 0;
   pthread_mutex_t n_lock = PTHREAD_MUTEX_INITIALIZER;
   pthread_t child1, child2;

   void *Child(void *args) {
      int i, temp;

      for (i = 0; i < N; i++) {
         pthread_mutex_lock(&n_lock);
         temp = n;
         temp++;
         n = temp;
         pthread_mutex_unlock(&n_lock);
      }
      return 0;
   }

   printf("initial n = %d\n", n);

   if (pthread_create(&child1, NULL, Child, NULL) != 0)
      SysError("main:pthread_create");
   if (pthread_create(&child2, NULL, Child, NULL) != 0)
      SysError("main:pthread_create");

   pthread_join(child1, NULL);
   pthread_join(child2, NULL);

   printf("final n = %d\n", n);

   return 0;
}

Скомпилировать с флагом -pthread в gcc.

0 голосов
/ 24 марта 2011

Согласно справочной странице для clone (), стек должен указывать на последний адрес в выделенной памяти.Ваша ссылка на "stack + STACK_SIZE" на самом деле находится за пределами выделенной памяти.

...