События(event) в boost'e
Мне потребовалось организовать "общение" между потоками. При этом нельзя зависеть от операционной системы (т.е. нельзя включить windows.h). Выбор пал на boost. Мьютексы понятно как сделать через boost::mutex. Но всё-таки требуется и нечто типа Event'a. Т.е. чтобы 1 поток мог создать это событие, и оно бы разрешало продолжить работу другому.
В общем виде:
поток А:
--делает, что надо....
--вызывает функцию, возвращающую bool и означающую, можно ли двигаться дальше
Соответственно, эта функция должна либо вернуть "можно" и всё забыть, либо отказать, но при этом сгенерировать событие, которое отправится потоку А, когда будет можно, чтобы он в цикле не опрашивал.
Кто-нибудь может подсказать, как такое сделать можно?
Мне потребовалось организовать "общение" между потоками. При этом нельзя зависеть от операционной системы (т.е. нельзя включить windows.h). Выбор пал на boost. Мьютексы понятно как сделать через boost::mutex. Но всё-таки требуется и нечто типа Event'a. Т.е. чтобы 1 поток мог создать это событие, и оно бы разрешало продолжить работу другому.
В общем виде:
поток А:
--делает, что надо....
--вызывает функцию, возвращающую bool и означающую, можно ли двигаться дальше
Соответственно, эта функция должна либо вернуть "можно" и всё забыть, либо отказать, но при этом сгенерировать событие, которое отправится потоку А, когда будет можно, чтобы он в цикле не опрашивал.
Кто-нибудь может подсказать, как такое сделать можно?
в вашем предыдущем абзаце вы как раз описываете работу мьютекса, поток пытается завладеть мьютексом, если мьютекс занят то поток блокируется и ожидает пока мьютекс не будет освобожден, как только мьютекс освобождается поток продолжает работу...
или же изъясняйтесь менее сумбурно, сложно понять чего вы хотите добиться. бо для меня до сих пор загадка, что вы хотели сказать фразой - "... Мьютексы понятно как сделать через boost::mutex. ..."...
Попытаюсь описать более подробно.
Есть некий класс - список из номеров. Каждый поток перед тем, как войти в определённую свою фазу, должен проверить, нет ли номера, с которым этот поток работает, в списке. Если нет, то дописывает номер в список и работает. После окончания работы (это очень недолгое время), поток должен удалить номер из списка. Если данный номер уже есть в списке, то поток должен заблокироваться до тех пор, пока этот номер из списка не удалят.
И вот я пытаюсь как-то это сделать. Самый примитивный вариант - в цикле проверять наличие номера, и если есть, то проверяем ещё и ещё, пока, наконец, не будет. Но это слишком нерационально. Поэтому хорошо бы уметь как-то оповещать, что номер из списка удалили и поток может продолжить работу
И вот я пытаюсь как-то это сделать. Самый примитивный вариант - в цикле проверять наличие номера, и если есть, то проверяем ещё и ещё, пока, наконец, не будет. Но это слишком нерационально. Поэтому хорошо бы уметь как-то оповещать, что номер из списка удалили и поток может продолжить работу
А если сделать наоборот: сделать управляющий класс, к которому обращаются потоки, чтобы получить очередное задание.
Естественно, управляющий класс должен быть потокобезопасным.
На случай, если снова непонятно объясняю, попробую объяснить пошире. Может, тут вообще что-то другое принято применять.
Есть 1 класс, к которому обращаются много потоков. Обращаются всегда используя 1 метод:
mainObj.mainMethod(int a);
соответственно, сам метод написан так, что позволяет, чтобы его одновременно могли вызвать много потоков. Но есть одно НО: вызовы эти должны быть с разными параметрами int a.
Представим, что 3 запроса приходят "одновременно". Вот так всё будет работать нормально:
thread1: method(1);
thread2: method(5);
thread3: method(8);
А вот при таких обстоятельствах, потоки 1 и 2 должны отрабатывать метод, а поток 3 ждать, пока поток1 не закончит выполнение этого метода:
thread1: method(1);
thread2: method(5);
thread3: method(1);
соответственно, в этом главном классе я сделал вложенный мелкий класс-список, де хранились числа, с которыми пришли потоки, что сейчас работают. Как только поток заканчивал метод, то убирал своё число из этого списка. Разумеется, я не могу держать хэндлов на каждый возможный номер. Поэтому думал обойтись одним: на вход в класс-список, который вызывается сразу при входе в mainMethod и говорит: подождать или продолжить выполнение
Да нет же, я предлагаю чтобы управляющий раздавал задания, а не говорил можно или нельзя.
То есть поток запускается и просит управляющего дать ему задание int Manager::GetTask()... Управляющий дает ему число, с которой надо работать потоку.
У управляющего есть массив чисел, и индекс в массиве, следующего элемента, который надо отдать на задание.
Когда все элементы отданы, надо на очередное требование сообщить потоку, что больше задач нет.
Например, как-нибудь так:
int Manager::GetTask(bool& received)
Попытаюсь описать более подробно.
Есть некий класс - список из номеров. Каждый поток перед тем, как войти в определённую свою фазу, должен проверить, нет ли номера, с которым этот поток работает, в списке. Если нет, то дописывает номер в список и работает. После окончания работы (это очень недолгое время), поток должен удалить номер из списка. Если данный номер уже есть в списке, то поток должен заблокироваться до тех пор, пока этот номер из списка не удалят.
И вот я пытаюсь как-то это сделать. Самый примитивный вариант - в цикле проверять наличие номера, и если есть, то проверяем ещё и ещё, пока, наконец, не будет. Но это слишком нерационально. Поэтому хорошо бы уметь как-то оповещать, что номер из списка удалили и поток может продолжить работу
только я почувствовал тягу назвать это моделью читателей-писателей?
есть один вопрос, поток должен работать с конкретным номером? то есть он не может работать с любым свободным, которого нет в списке?
я думаю,что примерно это должно работать так(насколько я понял из ваших описаний) пишите класс ГлавныйПоНомерам который будет садистки командовать потоками, заводите в оном диктаторе словарь ключами которого являются ваши преславутые номера, а значения мьютексы. При попытки поработать с номером поток обращется к мьютексу соответствующему данному номеру, если мьютекс занят поток блокируется и будет разблокирован когда номер освободиться, если мьютекс не занят, то поток его занимает, поработав освобождает. Это случай если поток не может работать с любым свободным номером, в противном случае тут классическая модель читатели-писатели, реализуются наиболее элегантно через семафоры, в сети уйма исходников и примеров.
представим, что служанка - это кэш.
Им пользуется много разных процессов, которые когда им заблагорассудится, просят страницы с харда. И кэш умеет работать со всеми сразу. Но если 2 потока просят одинаковую страницу одновременно, то кэш загрузит её в память 2 раза. И получится, что кэш неэффективен. Поэтому одновременно просить одинаковую нельзя. Сначала надо выполнить 1 запрос, загрузив страницу из харда в оперативку, а потом выполнить для второго, найдя страницу в памяти (т.к. уже загрузили) и вернув ссылку на неё.
(в примере мы пренебрегаем бытом, считая, что потоки, например, только читают страницы и не пишут в них)
Никто один не может знать, чего захотят потоки. Потоки - это люди. У них у каждого время от времени возникают желания. Различных желаний очень много (миллион), так что завести словарь по ним нельзя. И вот когда у очередного потока-человека возникает желание, он идёт к деду-морозу(наш главный объект). Дед-мороз - по сути просто исполнитель желаний. Он очень могуч и может одновременно исполнить сразу все возможные желания. Но вот беда: 2 одинаковых одновременно сделать не может. То есть он может подарить Васе Феррари, а Пете Мерседес, но 2 Мерседеса одновременно обоим не может. Если же так получилось, что они оба захотели, то Мерседес достаётся лишь одному, а второму сообщаем: "Не горюй, желание исполнится, только чуть позже". И со следующем волной, выполняем и это желание.
Проблема: Петю обнадёжили, и он через каждую секунду спрашивает: "не готово ли?". Тем самым очень надоедает деду-морозу. Но, конечно, всем хочется сделать всё побыстрее, поэтому было бы неправильным говорить Пете, что Мерседес будет, но завтра, если скорее всего он будет минут через 10-15:).
Я подумал, что для решения этой проблемы деду-морозу надо изобрести почтовых голубей, которые сами известят Петю, что всё готово и можно забирать. (поэтому и спрашивал про "событие"). Но если есть какая-то стандартная практика разрешения подобных проблем, то намекните, как поискать её... (требования только к кроссплатформенности)
представим, что служанка - это кэш.
Им пользуется много разных процессов, которые когда им заблагорассудится, просят страницы с харда. И кэш умеет работать со всеми сразу. Но если 2 потока просят одинаковую страницу одновременно, то кэш загрузит её в память 2 раза. И получится, что кэш неэффективен. Поэтому одновременно просить одинаковую нельзя. Сначала надо выполнить 1 запрос, загрузив страницу из харда в оперативку, а потом выполнить для второго, найдя страницу в памяти (т.к. уже загрузили) и вернув ссылку на неё.
(в примере мы пренебрегаем бытом, считая, что потоки, например, только читают страницы и не пишут в них)
Более-менее понятно, хотя что-то в этой схеме очень сильно смущает...
По делу: вместо событий можно просто вызывать публичные методы соответствующих классов.
Ожидание потока сделать с помощью boost::condition
(а что смущает?)
Даже не смогу сформулировать )) Возможно, не знаю специфики решаемой задачи и на самом деле это оптимальное решение и все отлично у Вас.