Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > потокобезопасноя очередь


Автор: shara 28.7.2011, 16:49
Собсвтенно сабж.  

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

З.Ы. А если и изобретать велосипед, то только с "блекджеокм и шлюхами", в смысле шобы без блокировок   smile   Возможно ли такое?

Автор: boostcoder 28.7.2011, 17:00
Цитата(shara @  28.7.2011,  16:49 Найти цитируемый пост)
кто как решает вопрос? 

изобретают велосипеды. потому как стандартных средств нет :(

Автор: svlary 29.7.2011, 05:05
Цитата(shara @  28.7.2011,  16:49 Найти цитируемый пост)
родных линуксовых средств нету... 

Не понял впроса... А чем Вас не устраивает :

Код

rc = mkfifo("FIFO", 0666);
fd = open("FIFO",...
len = write(fd,...
read(fd,...
close(fd);


Или Вы считаете эти системные вызовы НЕ безопасными ?

Автор: boostcoder 29.7.2011, 05:38
svlary, по идее, речь идет об http://cplusplus.com/reference/stl/queue/

Автор: azesmcar 29.7.2011, 08:34
Цитата(shara @  28.7.2011,  16:49 Найти цитируемый пост)
З.Ы. А если и изобретать велосипед, то только с "блекджеокм и шлюхами", в смысле шобы без блокировок   smile   Возможно ли такое? 

Возможно, но очень сложно (смотри lock-free queue, реализовать можно на основе односвязного списка). А зачем тебе?

Цитата(shara @  28.7.2011,  16:49 Найти цитируемый пост)
Вроде как родных линуксовых средств нету... а в очередной раз изобретать велосипед неохота. 

В интернете полно бесплатных библиотек, бери любую.

Автор: shara 29.7.2011, 10:03
Цитата(azesmcar @  29.7.2011,  07:34 Найти цитируемый пост)
 А зачем тебе?

Потому как очередь будет активно пользоваться в n-ом количестве потоков. 
И как-то не кошерно  получается,  что для вставки одного единственно элемента (в начало очереди) - приходится блокировать всю очередь, и не только вставка нового элемента становится на паузу,  но и чтение тоже, а ведь оно происходит с конца - эти два процесса теоретически друг другу не должны мешать. А еще хотелось бы, чтобы два и более процессов в случае одновременного чтения могли получить корректные данные, и также не блокировали друг друга. Ведь в большинстве случаев не важно в каком порядке они это сделают. Т.е. допустим что в очереди хранится элементы  A,B,C и допустим два потока пытаются одновременно читать из нее. И не важно прочитает ли первый процесс А а второй B, или наоборот - первому достанется B а второму A. Главное чтобы ни кто не прочитал С или вообще какой-нить XYz  smile     Где-то также дела будут обстоять и с записью.  

Пошуршал интернеты - нашел http://www.rsdn.ru/forum/philosophy/851251.all.aspx и еще http://habrahabr.ru/blogs/personal/102542/
А с Си, насколько  я понял, дело вообще обстоит туго - там стандарт не гарантирует (а точнее просто не парится по этому поводу) атомарности даже чтения значения переменной, не говоря уже об некой последовательности действий над ней, а жаль. Ведь имея возможность атомарно совершить всего ДВА действия над одним указателем (головы очереди в случаее записи, и над указателем хвоста - для для чтения) можно было бы избежать накладных расходов связанных с синхронизацией. 

Эх, мутекс в помощ да велосипед в придачу.. 

Автор: azesmcar 29.7.2011, 10:09
Цитата(shara @  29.7.2011,  10:03 Найти цитируемый пост)
И как-то не кошерно  получается,  что для вставки одного единственно элемента (в начало очереди) - приходится блокировать всю очередь, и не только вставка нового элемента становится на паузу,  но и чтение тоже, а ведь оно происходит с конца - эти два процесса теоретически друг другу не должны мешать. А еще хотелось бы, чтобы два и более процессов в случае одновременного чтения могли получить корректные данные, и также не блокировали друг друга. Ведь в большинстве случаев не важно в каком порядке они это сделают. Т.е. допустим что в очереди хранится элементы  A,B,C и допустим два потока пытаются одновременно читать из нее. И не важно прочитает ли первый процесс А а второй B, или наоборот - первому достанется B а второму A. Главное чтобы ни кто не прочитал С или вообще какой-нить XYz  smile     Где-то также дела будут обстоять и с записью.  

Если это действительно актуально (т.е. тебе это нужно не для успокоение совести, а задаче реально нужна высокая масштабируемость), то у тебя несколько вариантов.
1. reader-writer блокировки
2. lock-free
описание и того и другого можно найти по ссылке у меня в подписи.
Следует прогнать под профайлером и посмотреть на что в основном тратиться время и какое решение в твоем случае даст лучший результат. 
В общем сказать можно много чего, но мне как-то лень переписывать тоже самое smile 
просто перечитай эти две статьи
http://www.data-race.com/2011/02/01/readers-writers-%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8/
http://www.data-race.com/2011/02/04/lock-free-readers-writers/

Цитата(shara @  29.7.2011,  10:03 Найти цитируемый пост)
А с Си, насколько  я понял, дело вообще обстоит туго - там стандарт не гарантирует (а точнее просто не парится по этому поводу) атомарности даже чтения значения переменной

C++ тоже ничего не гарантирует по поводу атомарности.

Автор: svlary 1.8.2011, 06:02
Цитата(boostcoder @  29.7.2011,  05:38 Найти цитируемый пост)
речь идет об

Но ведь там написано :

Цитата

Container: Type of the underlying container object used to store and access the elements.


Я это понимаю так, что если в качестве контейнера использовать НАДЕЖНУЮ вещь типа системных FIFO сокетов, то и проблем не будет.  А если городить собственные городушки с мьютексами и прочими семафорами - то и получайте по полной программе. 

Автор: Dem_max 1.8.2011, 08:42
организуй для каждого потока свой FIFO, зачем с одним заморачиваться ?

Автор: shara 1.8.2011, 09:38
azesmcar, 
Цитата(azesmcar @  29.7.2011,  09:09 Найти цитируемый пост)
нужно не для успокоение совести

 именно для ее родимой. Ну я так подумал.... оно того не стоит. Намалюю себе простенькую очередь  =  будет мне счастье  smile
Это может быть потом, на досуге, поупражняюсь с lock-free операциями, и очередями в частности. Тема реально заинтересовала. За ссылочки спасибо  smile 


svlary,  
Цитата(svlary @  1.8.2011,  05:02 Найти цитируемый пост)
 то и получайте по полной программе

Простите не понял, получайте что? 
Ну я конечно понимаю что все функции семейства read\write проходят через системный кеш. Но мне кажется такая конструкция будет в любом случае работать медленнее, нежели самая примитивная самопальная реализация fifo. Реальное и неоспоримое достоинство Вашего метода в том, что он позволяет использовать очередь между отдельными процессами в системе (без лишних заморочек).


Dem_max, 
Оно то да, но даже при такой схеме возможно что два потока будут одновременно с ней работать (один пишет, второй читает). И посему, хоть раз в год,  но такое "ружье" обязательно выстрелит.  И мы опять возвращаемся на исходную (см. потокобезопасная очередь  smile )

Автор: Dem_max 1.8.2011, 09:48
Цитата

Оно то да, но даже при такой схеме возможно что два потока будут одновременно с ней работать (один пишет, второй читает)


Ну да, зато не будет простоя в потоках, когда один работает с FIFO а другие 30 потоков ждут доступа.
И я не говорю что данная схема будет потокобезопасной, тут дело в отсутствии простоев.

Автор: azesmcar 1.8.2011, 09:50
shara

расскажи о задаче поподробнее.

Автор: SenkraD 1.8.2011, 10:49
http://rsdn.ru/forum/cpp/3730905.1.aspx ещё одна неплохая статья на эту тему

Автор: shara 2.8.2011, 10:45
azesmcar, 
Многопоточный ssl-gateway:  с одной стороны (аля внешнее соединение) имеем ssl-соеденение с машиной A, с другой стороны (внутренее) открытое\незащищенное соединение с машиной B. Точки А и В логически соединены между собой gateway'ем

Собсно решил остановиться на такой архитектуре: 
в отдельном потоке вращается epool, который ждет событий на подключение\обслуживание соединений. 
при наступлении онных - раздает задачи (через очередь  smile  ) рабочим потокам
независимые потоки обслуживают ssl-соеденение (рукопожатие\шифровка\расшифровка) и организовывают передачу информации между двумя концами соединения ( А --> В или А <-- B).

С подачи Dem_max  smile решил каждому потоку выделить в руки по флагу по своей очереди. 
Тут конечно можно использовать lock-free очередь по сценарию (один пишет и один читает) но не охота "попасть в просак" из-за нюансов компилятора и перевода программы с С++ на Си (ибо как по условию задача должна решаться посредством последнего)
Да и думаю небольшие накладные расходы на синхронизацию доступа к очереди ничто по сравнению с тем временем которое потоки будут тратить на организацию ssl


SenkraD
Хороший материал, спасибо 



з.ы. реально на основе собранного в топике материала можно вкурить тему, взять готовую релицацию или склепать свою. 
Чем на досуге и хочу знаться. Думается мне, что в многопоточном программировании реализация lock-free очереди никогда не будет лишней


Автор: boostcoder 19.8.2011, 15:35
Цитата(shara @  2.8.2011,  10:45 Найти цитируемый пост)
в отдельном потоке вращается epool, который ждет событий на подключение\обслуживание соединений. 
при наступлении онных - раздает задачи (через очередь) рабочим потокам

изврат в действии smile 
Цитата

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

http://forum.vingrad.ru/forum/topic-336344.html

Добавлено через 2 минуты и 17 секунд
Цитата(shara @  2.8.2011,  10:45 Найти цитируемый пост)
Тут конечно можно использовать lock-free очередь

Цитата(shara @  2.8.2011,  10:45 Найти цитируемый пост)
Да и думаю небольшие накладные расходы на синхронизацию доступа к очереди

 -
Цитата

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

http://forum.vingrad.ru/forum/topic-336344.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)