LINUX.ORG.RU

Программируем критическую область (теория)


0

1

Короче, прочитал у Танненбаума (Э. Танненбаум, Современные Операционные Системы, 2-е изд., Питер, 2002) на стр. 132 про Алгоритм Петерсона, расчитанный на 2 процесса. И вдруг мне стало интересно как это будет выглядеть для N > 2 процессов. Решил наваять свой велосипед. Получилось вот такое:

#define N 100
#define FALSE 0
#define TRUE  1

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
int interested[N];
...
enter_region(int process){
 in++;
 turn = process;
 if(FALSE == interested[other]){
  nobody++;
  while(turn == process){
   if(1 == nobody && FALSE == interested[other]){
    choose_me = process;
    interested[process] = TRUE;
    other = choose_me;
   }
  }
  if(FALSE == interested[process]) {
   nobody--;
   interested[process] = TRUE;
  }
  while(other != process) 
   choose_me = process;
 }
}


leave_region(int process){
 interested[process] = FALSE;
 in--;
 if(in > 0){
  turn = process;
  while(process == choose_me);
  other = choose_me;
 }
 nobody--;
}


Мне кажется, что этот код гарантирует ожидаемое поведение (если пренебречь производительностью), а как думаете вы? Как бы вы это реализовали? Как бы доказывали гарантию?

Блин, лажанул таки, вот исправление на скорую руку:

...

#define N 100
#define FALSE 0
#define TRUE  1

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
int interested[N];
int decrement[N];
...
enter_region(int process){
 in++;
 turn = process;
 if(FALSE == interested[other]){
  nobody++;
  decrement[process] = TRUE;
  while(turn == process){
   if(1 == nobody && FALSE == interested[other]){
    choose_me = process;
    interested[process] = TRUE;
    other = choose_me;
   }
  }
  if(FALSE == interested[process]) {
   nobody--;
   decrement[process]  = FALSE;
   interested[process] = TRUE;
  }
  while(other != process) 
   choose_me = process;
 }
}


leave_region(int process){
 interested[process] = FALSE;
 in--;
 if(in > 0){
  turn = process;
  while(process == choose_me);
  other = choose_me;
 }
 if (TRUE == decrement[process])
  nobody--;
}

//fixed

gandjubas
() автор топика

Программируем критическую область (тория)


Из-за одного товарища из Молдовы, мне уже такое кажется.

zloy_buratino
()
Ответ на: комментарий от gandjubas

Я не программист, но раз настаиваешь... :)
По мне, так это непонятный набор слов и символов.

zloy_buratino
()
Ответ на: комментарий от AntonK

bool b = true; - вы про это? Это здесь не важно (теория). Я просто использовал те же обозначения, что и в книжке Танненбаума.

gandjubas
() автор топика
Ответ на: комментарий от AntonK

сам ты не принято. наоборот - так намного проще ловить ошибки типа один знак равенства вместо двух. так как в операции присваивания lvalue не может быть константой. отсюда практика - в сравнениях константы писать слева.

val-amart ★★★★★
()

И ещё один мелкий фикс


#define N 100
#define FALSE 0
#define TRUE  1

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
int interested[N];
int decrement[N];

...

enter_region(int process){
   in++;
   turn = process;
 
   if(FALSE == interested[other]){
      nobody++;
      decrement[process] = TRUE;
      
      while(turn == process){
         if(1 == nobody && FALSE == interested[other]){
            choose_me = process;
            interested[process] = TRUE;
            other = process;
            break;
         }
      }
   }      
   
   if(FALSE == interested[process]) {
      interested[process] = TRUE;
         
      nobody--;
      decrement[process]  = FALSE;
   }
      
   while(other != process) 
      choose_me = process;
   
   if(FALSE == decrement[process]){
      nobody++;
      decrement[process] = TRUE;
   }
}

leave_region(int process){
	interested[process] = FALSE;
	in--;
   
	if(in > 0){
		turn = process;
		while(process == choose_me)
			turn = process;
         
		other = choose_me;
	}
   
	nobody--;
	decrement[process]  = FALSE;
}

//fixed

Ну, вот теперь, наверное, можно уже задавать вопросы:

Мне кажется, что этот код гарантирует ожидаемое поведение (если пренебречь производительностью), а как думаете вы? Как бы вы это реализовали? Как бы доказывали гарантию?

gandjubas
() автор топика
Ответ на: И ещё один мелкий фикс от gandjubas

> а как думаете вы?
А мы думаем, что тебе нужно освоить тэг code и научиться комментировать свой код. Ибо без этого не возникает даже минимального желания в нём разбираться.

hdfan2
()
/*
 * Multi agents region concurrency pattern.
 */

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

/* Number of agents */
#define N 10

/* Priority table for agents
 *
 *   priority :: Agent -> Priority */
int priorityTable[N];

/* Last agent with priority
 *
 *   last :: Priority -> Agent */
int lastTable[N];

/* Wait and entry to the warm region */
void enter_region(int agent) {
  int priority, other;
  /* for each priority level */
  for (priority = 0; priority < N; priority++) {
    /* gradual warming of a priority */
    priorityTable[agent] = priority;
    lastTable[priority]  = agent;
    /* for other agents */
    for (other = 0; other < N; other++)
      if (other != agent)
        /* there is anyone hotter?.. */
        while (priorityTable[other] >= priorityTable[agent]
               && lastTable[priority] == agent)
          ;
  }
}

/* Leave the warm region - switching to zero priority */
void leave_region(int agent) {
  priorityTable[agent] = 0;
}

/* run pthread as agent */
void *run_thread(void* ptr) {
  int i, n = (int) ptr;
  printf("> %i begin\n", n);
  for(i = 0; i < 10; i++) {
    printf(">> %i wait\n", n);
    enter_region(n);
    printf(">>> *** %i in region\n", n);
    usleep(1000);
    printf(">>> *** %i in region\n", n);
    leave_region(n);
    printf(">> %i leave\n", n);
  }
  printf("> %i end\n", n);
}

main() {
  pthread_t threads[N];
  int returns[N];
  int i;

  for (i = 0; i < N; i++)
    returns[i] = pthread_create(&threads[i], NULL, run_thread, (void*) i);

  for (i = 0; i < N; i++)
    pthread_join(threads[i], NULL);

  for (i = 0; i < N; i++)
    printf("Thread %i returns: %d\n", i, returns[i]);

  exit(0);
}
quasimoto ★★★★
()
Ответ на: комментарий от AntonK

>На сях так писать не принято.

Можно еще так:

#define BEGIN {

#define END }

slackwarrior ★★★★★
()
Ответ на: комментарий от quasimoto

Хотя с помощью pthread тестировать - это не то. Я не знаю как это тестировать - наверно, проще запустить на голом железе под qemu :) Сделать рандомные задержки в процессах и смотреть - не окажутся ли два процесса в регионе (счётчик) и не будет ли deadlock-а. Насчёт верификации - доказать невозможность пребывания одновременно двух и более процессов в регионе - вроде решаемая задачка, а вот доказать что не существует deadlock-ов - намного сложнее.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

доказать невозможность пребывания одновременно двух и более процессов в регионе - вроде решаемая задачка, а вот доказать что не существует deadlock-ов - намного сложнее

Так уж и сложнее? Deadlock в enter_region() никогда не возникнет из-за отсутствия условия циклического ожидания. Пусть в произвольный момент времени m процессов пытаются пройти в критическую секцию. Выделим из этих m подмножество процессов с максимальным в данный момент приоритетом. Пусть их будет n. Из этих n только один застранет на проверке условия

while (priorityTable[other] >= priorityTable[agent]
               && lastTable[priority] == agent)

Остальные смело пойдут дальше.

fang
()
Ответ на: комментарий от quasimoto

А почему это при помощи pthreads тестировать такое - это не то? Кроме того, надо увеличить N хотя бы до 1500-2000 (если речь идет о pthreads), чтоб ускорить процесс появления упомянутых проблем, если они есть.

anonymous
()
Ответ на: комментарий от anonymous

А почему это при помощи pthreads тестировать такое - это не то?

Ну, можно грешить на то что невозможно управлять атомичностью из user-space.

Сделал N = 100, рассинхронизировал (вроде, usleep((n + 1) * (n + 1) * 1000);, в разных местах цикла) и ни deadlock-ов ни конфликтов не видно. Так что всё-таки можно тестировать :) Вариант TC тоже работает (чисто эмпирически).

quasimoto ★★★★
()
Ответ на: комментарий от fang

Остальные смело пойдут дальше.

Дальше - вход в критический регион, как они туда пойдут?) Туда как раз только один может проскользнуть - остальные висят в этом busy-while-waiting.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Кстати, там дальше по тексту про то, что такой подход плох тем, что использует активное ожидание - сжигать машинерию в холостом цикле это верх наглости. Так что нужно читать дальше. (А ещё дальше можно читать про формальные подходы к описанию параллельных программ.)

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

> Дальше - вход в критический регион

Дальше - имелось ввиду, что увеличат свой приоритет.

Туда как раз только один может проскользнуть - остальные висят в этом busy-while-waiting


До тех пор, пока тот процесс, имеющий приоритет N - 1, не покинет критическую секцию.

Такого, что все висят в enter_region(), а в критической секции никого нет, не будет.

fang
()
Ответ на: комментарий от anonymous

погуглил

> аффтар погугли семафор дейкстры и перестань велосипедить

Семафоры Дейкстры
...
Принципиальным в понимании семафоров является то, что операции P(S) и > V(S) предполагаются неделимыми

http://www.hpcc.unn.ru/files/HTML_Version/part5.html

Уточняю свою задачу: у нас нет неделимых операций, и в данном топике мы как раз пытаемся изобрести эти самые неделимые операции P(S) и V(S).

gandjubas
() автор топика
Ответ на: комментарий от hdfan2
#define N 100
#define FALSE 0
#define TRUE  1

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
int interested[N];
int decrement[N];

...
/* входим в критическую область */
enter_region(int process){
   in++;
   turn = process;
   /* other - захвативший ресурс, 
      проверяем что он уже ушёл из крит. секции */
   if(FALSE == interested[other]){
      nobody++;
      decrement[process] = TRUE;
      /* цикл выбраковки конкурентов - из него вылетают 
         все кроме последнего зашедшего */
      while(turn == process){
         if(1 == nobody && FALSE == interested[other]){
            choose_me = process;
            interested[process] = TRUE;
            other = process;
            break;
         }
      }
   }      
   /* все, вылетевшие из цикла выбраковки не солоно хлебавши,
      попадают в следующий иф и сбрасывают счётчик nobody,
      так что последний зашедший счастливо проваливается в иф выше,
      если other уже ушёл, и сам становится other-ом*/
   if(FALSE == interested[process]) {
      interested[process] = TRUE;
         
      nobody--;
      decrement[process]  = FALSE;
   }
   /*... и застревают здесь, 
      пока other не дошедший до leave_region 
      не выручит самого удачливого */   
   while(other != process) 
      choose_me = process;
   
   if(FALSE == decrement[process]){
      nobody++;
      decrement[process] = TRUE;
   }
}

/* покидаем критическую область */
leave_region(int process){
   interested[process] = FALSE;
   in--;
   /* сбросили счётчик входа,
      и проверяем не завис ли кто в enter_region  */   
   if(in > 0){
      turn = process;
      while(process == choose_me)
         turn = process;
      /*завис - значит проталкиваем его до слова choose_me, 
        (мимо цикла конкурентов - сбрасываем turn) 
        и назначаем other-ом*/   
      other = choose_me;
   }
   /* сбросили счётчик nobody,
      чтобы если когда никого нет, 
      новый счасливчик смог сам себя назначить other-ом */
   nobody--;
   decrement[process]  = FALSE;
}
gandjubas
() автор топика
Ответ на: комментарий от quasimoto

void enter_region(int agent) {
  int priority, other;
  /* for each priority level */
  for (priority = 0; priority < N; priority++) {
    /* gradual warming of a priority */
    priorityTable[agent] = priority;
    lastTable[priority]  = agent;
    /* for other agents */
    for (other = 0; other < N; other++)
      if (other != agent)
        /* there is anyone hotter?.. */
        while (priorityTable[other] >= priorityTable[agent]
               && lastTable[priority] == agent)
          ;
  }
}

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

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Мне кажется

Посмотрите выхлоп main, оно именно это и делает:

задержать всех входящих в крит. секцию независимо от их номера

Аналогичный выхлоп будет и у вашего варианта:

> 6 begin
>> 6 wait
>>> *** 6 in region
> 7 begin
>> 7 wait
> 8 begin
>> 8 wait
> 9 begin
>> 9 wait
> 5 begin
>> 5 wait
> 4 begin
>> 4 wait
> 3 begin
>> 3 wait
> 2 begin
>> 2 wait
> 1 begin
>> 1 wait
> 0 begin
>> 0 wait
>>> *** 6 in region
>> 6 leave
>>> *** 3 in region
>>> *** 3 in region
>> 3 leave
>>> *** 1 in region
>>> *** 1 in region
>> 1 leave
>>> *** 4 in region
>>> *** 4 in region
>> 4 leave
>>> *** 8 in region
>> 6 wait
>> 3 wait
>> 1 wait
>>> *** 8 in region
>> 8 leave
>>> *** 9 in region
>> 4 wait
>> 8 wait
>>> *** 9 in region
>> 9 leave
>>> *** 8 in region
>>> *** 8 in region
>> 8 leave
>>> *** 7 in region
>> 9 wait
>>> *** 7 in region
>> 7 leave
>>> *** 4 in region
>>> *** 4 in region
>> 4 leave
>>> *** 9 in region
>> 8 wait
>> 7 wait
>> 4 wait
>>> *** 9 in region
>> 9 leave
>>> *** 4 in region
>>> *** 4 in region
>> 4 leave
>>> *** 8 in region
>> 9 wait
>>> *** 8 in region
>> 8 leave
>>> *** 0 in region
>>> *** 0 in region
>> 0 leave
>>> *** 7 in region
>> 4 wait
>>> *** 7 in region
>> 7 leave
>>> *** 6 in region
>> 8 wait
>> 0 wait
>>> *** 6 in region
>> 6 leave
>>> *** 8 in region
>> 7 wait
>>> *** 8 in region
>> 8 leave
>>> *** 7 in region
>> 6 wait
>>> *** 7 in region
>> 7 leave
>>> *** 1 in region
>>> *** 1 in region
>> 1 leave
>>> *** 4 in region
>>> *** 4 in region
>> 4 leave
>> 8 wait
>>> *** 3 in region
>>> *** 3 in region
>> 3 leave
>>> *** 0 in region
>>> *** 0 in region
>> 0 leave
>>> *** 5 in region
>> 7 wait
>> 1 wait
>>> *** 5 in region
>> 5 leave

в регионе всегда только один процесс, пока не выйдет - потом другой процесс, тоже только один.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Хм, интересно, надо будет как нибудь разобраться с этим.

gandjubas
() автор топика

И ещё один фикс


#define N 100
#define FALSE 0
#define TRUE  1

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
int interested[N];
int decrement[N];

...
/* входим в критическую область */
enter_region(int process){
   in++;
   turn = process;
   /* other - захвативший ресурс, 
      проверяем что он уже ушёл из крит. секции */
   if(FALSE == interested[other]){
      nobody++;
      decrement[process] = TRUE;
      /* цикл выбраковки конкурентов - из него вылетают 
         все кроме последнего зашедшего */
      while(turn == process){
         if(1 == nobody && FALSE == interested[other]){
            choose_me = process;
            interested[process] = TRUE;
            other = process;
            break;
         }
      }
   } 
   else
      interested[process] = TRUE;
           
   /* все, вылетевшие из цикла выбраковки не солоно хлебавши,
      попадают в следующий иф и сбрасывают счётчик nobody,
      так что последний зашедший счастливо проваливается в иф выше,
      если other уже ушёл, и сам становится other-ом*/
   if(FALSE == interested[process]) {
      interested[process] = TRUE;
         
      nobody--;
      decrement[process]  = FALSE;
   }
   /*... и застревают здесь, 
      пока other не дошедший до leave_region 
      не выручит самого удачливого */   
   while(other != process) 
      choose_me = process;
   
   if(FALSE == decrement[process]){
      nobody++;
      decrement[process] = TRUE;
   }
}

/* покидаем критическую область */
leave_region(int process){
   interested[process] = FALSE;
   in--;
   /* сбросили счётчик входа,
      и проверяем не завис ли кто в enter_region  */   
   if(in > 0){
      turn = process;
      while(process == choose_me)
         turn = process;
      /*завис - значит проталкиваем его до слова choose_me, 
        (мимо цикла конкурентов - сбрасываем turn) 
        и назначаем other-ом*/   
      other = choose_me;
   }
   /* сбросили счётчик nobody,
      чтобы если когда никого нет, 
      новый счасливчик смог сам себя назначить other-ом */
   nobody--;
   decrement[process]  = FALSE;
}

//fixed

gandjubas
() автор топика
Ответ на: комментарий от quasimoto

А ну да, кажется понял как работает ваш вариант. Единственный недостаток, как мне кажется, что вам нужно пробежать весь массив от начала до конца, а значит вам нужно знать сколько всего у вас элементов в нём. А что, если у вас массив - динамическая структура (процессы рождают другие процессы)? Тогда у вас будет меняться N и когда вы будете сравнивать в циклах превышение над этим N, то однажды вы можете получить неверный результат и вылететь за границы массива.

gandjubas
() автор топика
Ответ на: И ещё один фикс от gandjubas

#define N 100

int other = 0;
int nobody = 0;
int in = 0;
int turn = 0;
int choose_me = 0;
bool interested[N];

...
/* входим в критическую область */
enter_region(int process){
   bool decrement = false;
   in++;
   turn = process;
   /* other - захвативший ресурс, 
      проверяем что он уже ушёл из крит. секции */
   if(!interested[other]){
      nobody++;
      decrement = true;
      /* цикл выбраковки конкурентов - из него вылетают 
         все кроме последнего зашедшего */
      while(turn == process){
         if(1 == nobody && !interested[other]){
            choose_me = process;
            interested[process] = true;
            other = process;
            break;
         }
      }
   } 
   else
      interested[process] = true;
           
   /* все, вылетевшие из цикла выбраковки не солоно хлебавши,
      попадают в следующий иф и сбрасывают счётчик nobody,
      так что последний зашедший счастливо проваливается в иф выше,
      если other уже ушёл, и сам становится other-ом*/
   if(!interested[process]) {
      interested[process] = true;
         
      nobody--;
      decrement  = false;
   }
   /*... и застревают здесь, 
      пока other не дошедший до leave_region 
      не выручит самого удачливого */   
   while(other != process) 
      choose_me = process;
   
   if(!decrement)
      nobody++;
}

/* покидаем критическую область */
leave_region(int process){
   interested[process] = false;
   in--;
   /* сбросили счётчик входа,
      и проверяем не завис ли кто в enter_region  */   
   if(in > 0){
      turn = process;
      while(process == choose_me)
         turn = process;
      /*завис - значит проталкиваем его до слова choose_me, 
        (мимо цикла конкурентов - сбрасываем turn) 
        и назначаем other-ом*/   
      other = choose_me;
   }
   /* сбросили счётчик nobody,
      чтобы если когда никого нет, 
      новый счасливчик смог сам себя назначить other-ом */
   nobody--;
}


gandjubas
() автор топика
Ответ на: комментарий от gandjubas

А что, если у вас массив - динамическая структура (процессы рождают другие процессы)?

Ну, то был небольшой код решающий конкретную проблему с одним регионом и фиксированным числом процессов. Даже учебную проблему. Мы же не планировщик общего назначения пишем?) Это будет уже совсем другой вопрос. Правда я не знаю зачем писать *ещё один* планировщик стандартного вида (типа O(1) из Linux, или того что для LWKT).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

> Ну, то был небольшой код решающий конкретную проблему с одним регионом и фиксированным числом процессов

Ха! в условии не сказано, что число процесов фиксировано :) «для N > 2 процессов»

gandjubas
() автор топика
Ответ на: комментарий от quasimoto

Это решение, а не условие. Тело обоих функций позволяет изменять структуру массива interested[] - как угодно. Это может быть даже «рваный» массив с внутренним представлением в виде связанного списка - у Джефа Элджера описано несколько фокусов, как можно это сделать с перегрузкой оператора [] - так, что сами функции (в моём варианте) - менять не надо вообще и при этом они будут, что называется, thread-safe.

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Можно ещё посмотреть в сторону STM - там есть некий прогресс в сторону locking-free (мониторы, семафоры, мьютексы - это всё реализация на locks).

quasimoto ★★★★
()

> Мне кажется, что этот код гарантирует ожидаемое поведение (если пренебречь производительностью), а как думаете вы?

Нет, нет, нет и ещё раз нет. Читать по теме:

* что такое consensus number и чему он равен для ячеек памяти, к которым применимы только операции записи и чтения (статья авторства Herlihy)

* out-of-order execution и последствия, связанные с изменением фактического порядка записи в память

* модель памяти процессора Alpha

bvvv
()
Ответ на: комментарий от bvvv

> Нет, нет, нет и ещё раз нет. Читать по теме:

Авторы приводимых источников не знакомы с алгоритмом приведённым мной (см. последний фикс) - т.к. я его выдумал буквально на днях. Если у вас есть сценарий поломки этого алгоритма, приведите его пожалуйста, очень интересно!

Впрочем, за источники спасибо, буду повышать свой скилл.

gandjubas
() автор топика
Ответ на: комментарий от bvvv

Впрочем одну уязвимость я могу вам назвать: если у нас бесконечное число процессов и они поступают в крит. секцию с определённой частотой - так что счётчик nobody никогда не сбрасывается в 1 в тот момент, когда предпоследний прибывший готов войти в первый иф в цикле конкурентов, то мы получим вечное ожидание. Но вероятность этого (см. «бесконечное число» и «определённая частота»)- стремится к нулю. Но я уверен, что тут тоже можно что-то придумать и сделать алгоритм идеальным.

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Ну и горячая правка на эту уязвимость такая: до in++; выполнить что-то типа if (!interested[other]) sleep(in); - заснуть на определённое число микросекунд. Каждый новый процесс будет спать всё дольше так что в конце концов гарантированно наступит момент, когда кто-то успеет прорваться и стать other-ом. Кстати, чтобы проц. почём зря не гонять, всех кто дошёл до команды choose_me можно также сделать спящими (вечно), но тогда в leave_region их нужно будить и если их больше одного, то и т.д. и т.п. На следующих выходных улучшу текущую версию, а сейчас работать надо :)

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Авторы приводимых источников формально доказывают, что любой алгоритм, который использует только ячейки памяти с операциями чтения и записи, не может реализовывать синхронизацию двух и более потоков.

int a = 0, b = 0;

void thread1(void)
{
  while(a == 0)
    ;

  print(b);
}

void thread2(void)
{
  sleep(rand());

  b = 42;
  a = 1;
}

Может ли этот код вывести 0? Если вы скажете что «нет», то вы не понимаете как работают современные процессоры. А если скажете что «да», то ваш алгоритм очевидным способом неправильный.

bvvv
()
Ответ на: комментарий от bvvv

И что ваш пример доказывает? Что синхронизировать вручную два процесса невозможно!? Мой код вы, похоже, даже не пытались осилить...

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Ваш код я внимательно прочитал и увидел там модификацию алгоритма Петерсона, который работает только на машинах с очень строгой моделью памяти, к которым все настоящие машины не относятся. А ответ на свой вопрос я всё ещё хочу услышать.

\

bvvv
()
Ответ на: комментарий от bvvv

Что значит очень строгая модель памяти? В любой момент времени в любую ячейку либо пишется какое-то значение, либо читается. Чего-то среднего - не предполагается по модели данной задачи. Тогда всё должно работать. Другое дело что вы можете спросить: а как так получилось, что процессы у нас есть (гляди-ка даже усыплять и пробуждать их умеем!), а синхронизации между ними нет? Ну да, проблема видится несколько надуманной.

gandjubas
() автор топика
Ответ на: комментарий от bvvv

Не может, иначе будет нарушена причинно-следственная связь. Что бы кто не доказывал (и не реализовывал вкривь и вкось).

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

> В любой момент времени в любую ячейку либо пишется какое-то значение, либо читается.

Ага. А значение, видимое процессорами в один и тот же момент — разное! Как такое получается? Читайте:

Что такое модель памяти — гуглить по фразе memory consistency model. Под очень строгой я подразумеваю sequential model.

Также читать первые разделы linux-src/Documentation/memory-barriers.txt

bvvv
()
Ответ на: комментарий от bvvv

> А значение, видимое процессорами в один и тот же момент — разное!

И?

gandjubas
() автор топика
Ответ на: комментарий от gandjubas

Не может, иначе будет нарушена причинно-следственная связь. Что бы кто не доказывал (и не реализовывал вкривь и вкось).


В том-то и дело, что в не-sequential модели памяти причинно-следственная связь нарушается. Почитайте всё-таки об этом.

bvvv
()
Ответ на: комментарий от bvvv

Вы наверное про конвейеры, типа один рассчитал свою траекторию полёта (0), а другой - другую (42), так? Но напечатано-то будет 42, как ни крути (см. причинно-следственная связь). Что-либо другое - ошибка реализации механизма многопоточности.

gandjubas
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.