Здравствуйте, What, Вы писали:
W>Здравствуйте, Pzz, Вы писали:
Pzz>>Здравствуйте, What, Вы писали:
W>>>Здравствуйте, Pzz, Вы писали:
Pzz>>>>Но есть и более тонкая проблема. Процессор тоже может менять порядок доступа к памяти. Это заметно только если потоки бегут на разных процессорах в многопроцессорной системе (процессор с hyperthreading'ом ведет себя в этом отношении как 2 отдельных процессора). Проявляться это будет в том, что Ваша програмка будет изредка сбоить, причем эффект будет пропадать (или усиливаться, в зависимости от Вашего везения) под отладчиком, при вставлении отладочной печати и т.п. Лечится это с помощью memory barrier'ов, ищите подробности в интернете, мне на эту тему лень лекцию читать. W>>>Это верно для всяких там итаниумов и прочих, а на x86 и Intel64/AMD64 такой проблемы нет.
Pzz>>Я тоже так раньше думал, пока сам не нарвался. У меня, к счастию, не было Вашей уверенности, поэтому мне хватило часа, чтобы локализовать проблему, и полдня, чтобы сообразить, как переделать виноватое место. Подумайте на досуге, сколько времени это могло бы занять у Вас.
Я нисколько не пропагандирую использование volatile и не считаю это хорошей практикой. Действительно, существует проблема с необходимостью использования барьеров на не x86/Intel64/AMD64 платформах.
W>Однако наличие ошибки где-то у Вас в коде вряд ли является убедительным опровержением того, что x86 & co используют strict memory model (это, кстати, можно погуглить). W>неплохой пост про volatile, etc
Хотя бы прочитай о чём там написано.
А написано там про язык C#. А ключевое слово volatile в C# как раз подразумевает генерацию барьера памяти. Именно потому, что барьеры памяти на x86 нужны.
Это всё в отличие от С++, где volatile директива исключительно для компилятора.
Здравствуйте, What, Вы писали:
W>Однако наличие ошибки где-то у Вас в коде вряд ли является убедительным опровержением того, что x86 & co используют strict memory model (это, кстати, можно погуглить).
Довольно оскорбительная точка зрения
Я вообще человек довольно дотошный, и загадочные явления изучаю до того момента, когда я уверен, что докопался до источника проблемы. "Попробовали это, и все заработало" — это не мой метод. В данном случая я свой код отладочными печатями поймал за тем, что, грубо говоря, последовательность действий типа
i = 1; j = 2;
выглядит совершенно другой с соседнего процессора. Т.е., в j уже 2, а в i вовсе не 1.
Вы можете и дальше продолжать верить в свои заблуждения. Беда только в том, что поймать такую ошибку может занять у Вас от недели до бесконечности. Никакие отладчики Вам в этом не помогут. Могу лишь пожелать Вам удачи в этом деле.
P.S. Забыл сказать, Интеловскую документацию по x86 по этому вопросу я тоже, разумеется, изучил. Позиция Интела совпадает с моей. Грубо говоря, она сводится к тому, что memory ordering не виден, пока Вы остаетесь на одном процессоре, но с другого процессора он может выглядеть по-другому, если не предпринимать специальных усилий.
Re[6]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, remark, Вы писали:
R>Это полный бред, что на x86 не нужно использовать барьеры памяти при написании примитивов синхронизации.
В x86 в некоторых случаях не нужно использовать барьеры памяти там, где они нужны для других архитектур.
R>Дабы не ходить вокруг, да около: R>Intel® 64 Architecture Memory Ordering White Paper
Оттуда:
1. Loads are not reordered with other loads.
2. Stores are not reordered with other stores.
3. Stores are not reordered with older loads.
4. Loads may be reordered with older stores to different locations but not with older
stores to the same location.
Вовзращаясь к очереди автора топика, где там нужны memory barriers, исходя из спецификации выше? (Я согласен, что надо подобавлять volatile).
W>>неплохой пост про volatile, etc
R>Хотя бы прочитай о чём там написано.
Естественно, читал. R>А написано там про язык C#. А ключевое слово volatile в C# как раз подразумевает генерацию барьера памяти. Именно потому, что барьеры памяти на x86 нужны. R>Это всё в отличие от С++, где volatile директива исключительно для компилятора.
Там разбирается достаточно простой пример проблемы с переупорядочиванием инструкций, а по ссылкам есть Java и C++ memory model (то, что ты написал, что volatile не гарантирует барьер), а также интересные комментарии про барьеры в .net:
THE X86 MODEL.
The X86 has a relatively strong model. It states that all memory writes
can not pass one another. Bascially every write is a WriteMemoryBarrier.
What that means is that on the X86 the LazyInit example will never display
a problem. In particular on the X86 the
System.Threading.Thread.WriteMemoryBarrier() API is a no-op. On other
processors however it is important to have the barrier there.
CAVEATES for V1
Unfortunately, the MemoryBarrier APIs do not exist in the V1 product (they
were not a priority since V1 only supports the X86 and as we have seen,
code will work properly on the X86 without the MemoryBarrier calls.
These APIs have already been added what will be the next version of the
platform (to ship with Windows XP server). If you are concerned about
this issue, I would recommend you add the MemoryBarrier calls in the
correct places, and then comment them out until such time as you upgrade
to the next version of DOTNET.
Re[7]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, What, Вы писали:
W>Здравствуйте, remark, Вы писали:
R>>Это полный бред, что на x86 не нужно использовать барьеры памяти при написании примитивов синхронизации.
W>В x86 в некоторых случаях не нужно использовать барьеры памяти там, где они нужны для других архитектур.
С этим согласен. Но эта фраза не несёт практически никакой информации. Во-первых, потому что она справедлива практически для любой архитектуры. Во-вторых, она не несёт никакой информации, которую можно использовать на практике.
Тем не менее фраза "... на x86 и Intel64/AMD64 такой проблемы нет" не верна.
W>1. Loads are not reordered with other loads.
W>2. Stores are not reordered with other stores.
W>3. Stores are not reordered with older loads.
W>4. Loads may be reordered with older stores to different locations but not with older
W>stores to the same location.
W>Вовзращаясь к очереди автора топика, где там нужны memory barriers, исходя из спецификации выше? (Я согласен, что надо подобавлять volatile).
Это не совсем точно. Документ построен в виде "здесь некоторые правила. А здесь случаи, когда предыдущие правила не работают. А здесь оставшиеся правила". Смотри раздел 2.4 — он вносит некоторые усложнения.
W>>>неплохой пост про volatile, etc
R>>Хотя бы прочитай о чём там написано. W>Естественно, читал. R>>А написано там про язык C#. А ключевое слово volatile в C# как раз подразумевает генерацию барьера памяти. Именно потому, что барьеры памяти на x86 нужны. R>>Это всё в отличие от С++, где volatile директива исключительно для компилятора.
W>Там разбирается достаточно простой пример проблемы с переупорядочиванием инструкций, а по ссылкам есть Java и C++ memory model (то, что ты написал, что volatile не гарантирует барьер), а также интересные комментарии про барьеры в .net:
Интересно, откуда они взяли модель памяти для С++? Её же ещё нет...
Здравствуйте, Сергей Мухин, Вы писали:
СМ>Здравствуйте, remark, Вы писали:
R>>Очередь с использованием только неблокирующих примитивов (InterlockedXXX) на многопроцессорной/многоядерной машине может дать выигрыш на порядки по сравнению с очередью на мьютексе. Это можно частично вылечить, если использовать спин-мьютекс с активным ожиданием и с backoff'ом в блокировку, который (мьютекс, а не backoff) вызывает только одну InterlockedXXX операцию при захвате мьютекса.
R>>Очередь, типа предложенной, которая использует только голые сохранения и загрузки и дружественна расслабленной модели памяти современных аппаратных платформ, может дать выигрышь ещё на порядок по сравнению с очередью, использующей InterlockedXXX.
СМ>спасибо.
СМ>это, как я понимаю, если не учитывать ограниченность предложенной реализации.
СМ>т.е. мы сравниваем ограниченную по числу читателей-писателей, по алгоритму использования, при идеальной (для данной реализации) нагрузке с общем решением. Тогда будем иметь вышеприведённые выгоды по скорости. т.е. может использоваться автором в ограниченных задачах.
СМ>если перевести: велосипед на одном квадратном колесе ездит по одной тропинке быстро.
Проблема в том, что если ты используешь подход основанный на мьютексах, то у тебя очередь_много_производителей_много_потребителей == очередь_много_производителей_один_потребитель == очередь_один_производитель_много_потребителей == очередь_один_производитель_один_потребитель.
Т.е. если даже тебя бы устроила очередь_один_производитель_один_потребитель ты обязан иметь те же издержки, что и для очередь_много_производителей_много_потребителей.
Если ты используешь подход основанный не на мьютексах, то ты можешь взять специализированную реализацию для конкретной цели.
Т.е. фактически это сравнение можно рассматривать как сравнение очередь_один_производитель_один_потребитель, основанная на блокировках, против очередь_один_производитель_один_потребитель, основанная на неблокирующем подходе.
Второй момент, что очередь_один_производитель_один_потребитель значительно интереснее, чем кажется на первый взгляд. Во-первых, она имеет на порядок меньшие издержки и дружественность к SMP/multicore, чем все остальные типы очередей. Во-вторых, на основе этой очереди можно построить общее решение. Например, можно сделать полносвязанную систему из потоков, связанную такими очередями, где каждый поток может послать сообщение каждому. Либо можно построить систему, в которой один или несколько потоков выступают в роли посредников-маршрутизаторов, рядовые потоки связаны очередями с этимим посредниками и через них посылают/принимают сообщения от всех остальных потоков.
Такая система получается врожденно распределенной и как следствие — масштабируемой. Т.е. конкуренция на никакой очереди не растёт всё больше и больше с ростом числа процессоров/ядер.
Здравствуйте, remark, Вы писали:
W>>В x86 в некоторых случаях не нужно использовать барьеры памяти там, где они нужны для других архитектур.
R>С этим согласен. Но эта фраза не несёт практически никакой информации. Во-первых, потому что она справедлива практически для любой архитектуры. Во-вторых, она не несёт никакой информации, которую можно использовать на практике. R>Тем не менее фраза "... на x86 и Intel64/AMD64 такой проблемы нет" не верна.
Ок, переформулируем. В коде, предложенном автором топика, я не вижу проблемы с барьерами памяти (для x86 & co) и, соответственно, необходиости их использования.
W>>Вовзращаясь к очереди автора топика, где там нужны memory barriers, исходя из спецификации выше? (Я согласен, что надо подобавлять volatile).
R>Это не совсем точно. Документ построен в виде "здесь некоторые правила. А здесь случаи, когда предыдущие правила не работают. А здесь оставшиеся правила". Смотри раздел 2.4 — он вносит некоторые усложнения.
Да, вносит. Но всё равно, где нужны memory barriers в коде автора топика?
Re[9]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, What, Вы писали:
R>>С этим согласен. Но эта фраза не несёт практически никакой информации. Во-первых, потому что она справедлива практически для любой архитектуры. Во-вторых, она не несёт никакой информации, которую можно использовать на практике. R>>Тем не менее фраза "... на x86 и Intel64/AMD64 такой проблемы нет" не верна.
W>Ок, переформулируем. В коде, предложенном автором топика, я не вижу проблемы с барьерами памяти (для x86 & co) и, соответственно, необходиости их использования.
В коде автора конкретно на текущей модели памяти x86 барьеры памяти не нужны.
Если, конечно, он работает на типе памяти write-back, а не на write-combined
Но вот если надо будет к этой очереди прикрутить блокирующую dequeue(), которая блокируется пока не появяться новые элементы, то барьер памяти уже понадобится при каждом добавлении элемента.
Здравствуйте, remark, Вы писали:
R>Но вот если надо будет к этой очереди прикрутить блокирующую dequeue(), которая блокируется пока не появяться новые элементы, то барьер памяти уже понадобится при каждом добавлении элемента.
Как я уже писал, мне блокировка не нужна, так что все должно работать.
Re[6]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, Pzz, Вы писали:
W>>Однако наличие ошибки где-то у Вас в коде вряд ли является убедительным опровержением того, что x86 & co используют strict memory model (это, кстати, можно погуглить).
Pzz>Довольно оскорбительная точка зрения
Ну Вы тоже за словом в карман не лезете.
Pzz>Я вообще человек довольно дотошный, и загадочные явления изучаю до того момента, когда я уверен, что докопался до источника проблемы. "Попробовали это, и все заработало" — это не мой метод.
Я ничуть не сомневаюсь в Вашей дотошности. Однако, я уверен в том, что бы обобщаете проблему.
Потому что: Pzz>В данном случая я свой код отладочными печатями поймал за тем, что, грубо говоря, последовательность действий типа
i = 1; j = 2;
выглядит совершенно другой с соседнего процессора. Т.е., в j уже 2, а в i вовсе не 1.
Это ваше утверждение явно противоречит доке от Интел (спасибо remark'у):
2.1 Loads are not reordered with other loads and stores are not
reordered with other stores
Intel 64 memory ordering ensures that loads are seen in program order, and that stores are
seen in program order.
Processor 0 Processor 1
mov [ _x], 1 // M1 mov r1,[_y] // M3
mov [ _y], 1 // M2 mov r2, [_x] // M4
Initially x == y == 0
r1 == 1 and r2 == 0 is not allowed
Pzz>Вы можете и дальше продолжать верить в свои заблуждения. Беда только в том, что поймать такую ошибку может занять у Вас от недели до бесконечности. Никакие отладчики Вам в этом не помогут. Могу лишь пожелать Вам удачи в этом деле.
Ну вот, Вы опять грубите. Думаю, пора сворачивать эту дискуссию. Pzz>P.S. Забыл сказать, Интеловскую документацию по x86 по этому вопросу я тоже, разумеется, изучил. Позиция Интела совпадает с моей.
Всё таки она отличается от Вашей. Pzz>Грубо говоря, она сводится к тому, что memory ordering не виден, пока Вы остаетесь на одном процессоре, но с другого процессора он может выглядеть по-другому, если не предпринимать специальных усилий.
Вот, я и говорю, что обобщаете
На самом деле, я тоже считаю, что не стоит полагаться на такие эзотерические вещи, как последовательность доступа к памяти в разных потоках, и что лучше использовать как можно более высокоуровневые средства параллельного выполнения задач, в крайнем случае использовать библиотечные атомарные операции и мьютексы.
Но, возвращаясь к Вашим комментариям автору топика, проблем с переупорядочиванием инструкция на x86 и Intel64/AMD64 в исходном коде автора я не вижу, хотя согласен, что в принципе, а абстрактном коде они могут возникнуть очень легко.
Re[7]: Неблокируемая очередь сообщений для двух потоков
Да, я вероятно несколько упростил. В той же доке от Intel в пункте 2.3 сказано:
[q]
Intel 64 memory ordering allows load instructions to be reordered with prior stores to a
different location. However, loads are not reordered with prior stores to the same location.
The first example in this section illustrates the case in which a load may be reordered with an
older store – i.e. if the store and load are to different non-overlapping locations.
Processor 0 Processor 1
mov [ _x], 1 // M1 mov [ _y], 1 // M3
mov r1, [ _y] // M2 mov r2, [_x] // M4
Initially x == y == 0
r1 == 0 and r2 == 0 is allowed
[q]
Собственно, на что-то такое я и нарвался в реальном коде. Тоже попытался выпендриться, и сделать lock free в типичном случае
W>Но, возвращаясь к Вашим комментариям автору топика, проблем с переупорядочиванием инструкция на x86 и Intel64/AMD64 в исходном коде автора я не вижу, хотя согласен, что в принципе, а абстрактном коде они могут возникнуть очень легко.
Возможно вокруг именно добавления/удаления проблем нет — нет сил вычитывать, простите. Т.е., я готов допустить, что указатель на добавленный объект "читающий" поток получит правильный, и совместными усилиями очередь они не порушат. Однако из-за reordering'а load и store в different location есть вполне реальный шанс получить валидный указатель на объект, внутрь которого store еще не завершились.
Если бы очередь была защищена нормальным мутексом, это не было заметно, поскольку мутекс включает в себя memory barrier. InterlockedXXX на интеле тоже включает глобальный барьер, хотя микрософтовская документация этого не обещает (т.е., на других CPU это может быть и не так).
Re[8]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, Pzz, Вы писали:
Pzz>Возможно вокруг именно добавления/удаления проблем нет — нет сил вычитывать, простите. Т.е., я готов допустить, что указатель на добавленный объект "читающий" поток получит правильный, и совместными усилиями очередь они не порушат. Однако из-за reordering'а load и store в different location есть вполне реальный шанс получить валидный указатель на объект, внутрь которого store еще не завершились.
Как раз пункт 2.1 (который я цитировал) также гарантирует, что объект будет валидным. Если сначала записать сам объект (первая переменная), а потом положить указатель на него в очередь (вторая переменная внутри очереди), то, в момент, когда второй поток прочитает новое значение второй переменной (достанет из очереди указатель) первая переменная (содержимое объекта) будет уже иметь валидное знаечение, потому что она была записана раньше, а операции записи в разные адреса из одного потока не переставляются в x86. Так что конкретно в том коде автора темы барьеры доступа к памяти не нужны.
Хотя Вы безусловно правы, что шаг влево или вправо в коде очереди может привести к очень трудно обнаруживаемой и отлаживаемой ошибке, поймать которую "может занять у меня от недели до бесконечности".
Pzz>Если бы очередь была защищена нормальным мутексом, это не было заметно, поскольку мутекс включает в себя memory barrier.
+1
Re: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, HaronK, Вы писали: HK> ...Недавно возникла задача написания очереди для передачи сообщений от одного потока другому.
Очередь на основе циклического массива Вам не подойдет?
Один указатель(index) для записи и один для чтения. max — максимальное значение индексов, если больше, index=0
Если индекс чтения=индексу записи, то очередь пуста.
С уважением, Владимир.
Re[9]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, What, Вы писали:
W>Как раз пункт 2.1 (который я цитировал) также гарантирует, что объект будет валидным. Если сначала записать сам объект (первая переменная), а потом положить указатель на него в очередь (вторая переменная внутри очереди), то, в момент, когда второй поток прочитает новое значение второй переменной (достанет из очереди указатель) первая переменная (содержимое объекта) будет уже иметь валидное знаечение, потому что она была записана раньше, а операции записи в разные адреса из одного потока не переставляются в x86. Так что конкретно в том коде автора темы барьеры доступа к памяти не нужны.
При условии, что объект будет читаться в том же порядке, в котором он писался. Что является в нормальной жизни совершенно невыносимым требованием.
Я, кстати, читал не white paper, а другой интеловский дукомент, и поэтому у меня сложилось несколько другое (более пессемистическое) впечатление. Посмотрите пункт 7.2.2, там прям картинка нарисована про то, как writes с разных процессоров могут быть reordered. Следует учесть так же, что на SMP машинке поток вполне может перескочить на соседний процессор как раз между инструкциями, так что даже запись в одно и то же место может приехать out of order, если специально не позаботиться об обратном. Хотя, конечно, в процессе перескакивания на соседний процессор наверняка хоть один барьер да встретится, так что эта возможность скорее гипотетическая. Но я, знаете ли, в таких вопросах пессемист
Re[10]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, Pzz, Вы писали:
Pzz>При условии, что объект будет читаться в том же порядке, в котором он писался. Что является в нормальной жизни совершенно невыносимым требованием.
??
Достаточно читать (в любом порядке) после того, как объект достали из кучи.
Pzz>Я, кстати, читал не white paper, а другой интеловский дукомент, и поэтому у меня сложилось несколько другое (более пессемистическое) впечатление. Посмотрите пункт 7.2.2, там прям картинка нарисована про то, как writes с разных процессоров могут быть reordered. Следует учесть так же, что на SMP машинке поток вполне может перескочить на соседний процессор как раз между инструкциями, так что даже запись в одно и то же место может приехать out of order, если специально не позаботиться об обратном. Хотя, конечно, в процессе перескакивания на соседний процессор наверняка хоть один барьер да встретится, так что эта возможность скорее гипотетическая. Но я, знаете ли, в таких вопросах пессемист
Ну это совсем уже пессемистично
Re[11]: Неблокируемая очередь сообщений для двух потоков
remark wrote: > > > H>По > H>скорости — я не думаю, что реализация очереди на блокировках будет > H>существенно медленнее. Если вообще будет. > > > На однопроцессорной машине она может быть лучше более чем на порядок. На
Это при привой реализации потоков. При нормальной нет. Я вот не
поленился, попробовал простенькую реализацию очередей сделанную из тех
же соображений (правда получилось — один читатель, много писателей).
Результат — неблокирующая выигрывает процентов на 15-20 (в основном за
счет тормозов на InterlockedXXX операциях). И это вполне объяснимо — при
взаимодействии 1:1 в указанных условиях можно обойтись без фактических
блокировок. Вот код:
template <class TYPE>
class QueueMutex
{
public:
QueueMutex(size_t heap_size);
~QueueMutex();
void Enqueue(const TYPE& data);
bool Dequeue(TYPE& data);
private:
struct Element
{
TYPE data;
Element* next;
Element(const TYPE& _data) : data(_data), next(NULL) {}
};
Element * rqueue;
volatile Element * whead, * wtail;
Alloc<Element> heap;
Mutex writer_cs;
};
template <class TYPE>
QueueMutex<TYPE>::QueueMutex(size_t heap_size)
: heap(heap_size)
{
rqueue = NULL;
whead = wtail = NULL;
}
template <class TYPE>
QueueMutex<TYPE>::~QueueMutex()
{
}
template <class TYPE>
void QueueMutex<TYPE>::Enqueue(const TYPE& data)
{
Element * n = heap.alloc(data);
writer_cs.lock();
if (whead == NULL)
whead = n;
else
wtail->next = n;
writer_cs.unlock();
// если писателей много это присвоение нужно внести в
// критическую секцию
wtail = n;
}
template <class TYPE>
bool QueueMutex<TYPE>::Dequeue(TYPE& data)
{
Element * next = rqueue;
if (next == NULL) {
next = (Element *)whead;
if (next == NULL)
return false;
writer_cs.lock();
whead = NULL;
writer_cs.unlock();
}
data = next->data;
rqueue = next->next;
heap.release(next);
return true;
}
Из отличий — я эксперементировал с неблокирующим аллокатором (иначе
new/delete тоже занимаются сериализацией) и с разными мьютексами. По
порядку снижения производительности: spin lock, моя реализация
рекурсивного mutex с блокировками и win32 critical_section.
> многопроцессорной машине выигрыш будет ещё существеннее + иметь > последствия не только на голую скорость, но и на масштабиремость. >
С масштабируемостью, ИМХО, совсем не очевидно — реализация-то рассчитана
на взаимодействие 1:1. При таких условиях и блокирующие алгоритмы не
будут деградировать.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, vmoiseev, Вы писали:
V>Очередь на основе циклического массива Вам не подойдет? V>Один указатель(index) для записи и один для чтения. max — максимальное значение индексов, если больше, index=0 V>Если индекс чтения=индексу записи, то очередь пуста.
А для доступа к индексам блокировка не нужна?
Re: Неблокируемая очередь сообщений для двух потоков
Переписал реализацию очереди с учетом предложений в топике.
Из изменений:
1. Убрал флаг. Теперь его роль исполняет указатель на промежуточную цепочку.
2. Убрал new/delete. Операции создания и удаления возлагаются на потоки.
Не знаю насколько замена флага на указатель безопасна, но в моих тестах этот код отрабатывал.
Барьеры пока не добавлял, поскольку нет единого мнения нужны ли они вообще.
Получилось меньше операций и по идее должно быть быстрее.
Не знаю правда как повлияет на быстродействие второй volatile.
Здравствуйте, remark, Вы писали:
R>Второй момент, что очередь_один_производитель_один_потребитель значительно интереснее, чем кажется на первый взгляд. Во-первых, она имеет на порядок меньшие издержки и дружественность к SMP/multicore, чем все остальные типы очередей. Во-вторых, на основе этой очереди можно построить общее решение. Например, можно сделать полносвязанную систему из потоков, связанную такими очередями, где каждый поток может послать сообщение каждому. Либо можно построить систему, в которой один или несколько потоков выступают в роли посредников-маршрутизаторов, рядовые потоки связаны очередями с этимим посредниками и через них посылают/принимают сообщения от всех остальных потоков. R>Такая система получается врожденно распределенной и как следствие — масштабируемой. Т.е. конкуренция на никакой очереди не растёт всё больше и больше с ростом числа процессоров/ядер.
Я тоже думал о реализации варианта многие ко многим,а вот идея маршрутизатора интересна. Сейчас думаю над ее реализацией.
Re[3]: Неблокируемая очередь сообщений для двух потоков
Здравствуйте, HaronK, Вы писали: HK>А для доступа к индексам блокировка не нужна?
Думаю, что нет. Каждый поток меняет только свой индекс.
С уважением, Владимир.