Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: JamS007 от Июль 28, 2010, 22:56



Название: Не блокирующий обмен данными между потоками
Отправлено: JamS007 от Июль 28, 2010, 22:56
Приветствую, господа.

Задача: Есть сервер. При инициализации создаю пул служебных потоков. (-1 от количества ядер на машине или 1, если ядро одно). В основном потоке подключаються клиенты и читаються запросы от них. Также в основном потоке декодируються запросы от клинтов, и в зависимости от запроса "напрягаеться" служебный поток. Служебные потоки должны выполнять потенциально медленные задачи (чтение/запись с HDD, всевозможные проверки, и т.д.)

Хочу сделать максимально продуктивный сервер, в рамках Qt (другое не предлагать), поэтому, стараюсь комбинировать асинхронность с многопоточностью. Если есть идеи - с удовольствием выслушаю.

Цель: Среди задач выполняемых служебными потоками, есть такие, которые требуют подтверждения успешного выполнения. И тут возникает проблема:

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

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

Заранеее спасибо, даже за внимание :)


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: BlackTass от Июль 29, 2010, 00:46
Ну не блокировать основной поток можно посредством проброса сигнала из рабочего в основной по завершении. Главное только таски между собой различить по какому-нить ид.

Про очередь не понял вопроса. В том порядке в каком приходят в том и ставьте, ну или если есть приоритеты у тасков, то тасуйте слегка очередь/делайте несколько очередей (как в консульствах).


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: JamS007 от Июль 29, 2010, 10:59
Про сигналы я уже думал. Они действительно не блокируют основной поток поток, но на сигналы не приходит ответ, тоесть сигнал выслан, и все, как он там дальше будет обрабатыватся уже не известно.

Можно конечно сделать такуй связку сигналов:

Основной поток  --- (запрос) ---> дочерний поток
Дочерний поток  --- (ответ)   ---> основной поток

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

Тут, конечно, тоже можно выкрутиться, например прысилать какой-нибудь идентификатор запроса, но у меня команды записываються в ByteArray, и он весит порядка 40кб. (Знаю, много) И таскать каждый раз эту команду в поток и назад не хочеться.

Есть идеи?


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: BlackTass от Июль 29, 2010, 11:13
Я про это и имел в виду когда писал про ид. Основной поток присылает вместе с запросом его уникальный ид (который сам генерит банальным инкрементом). Дочерний поток присылает ответ вместе с этим идшником и основной поток уже смотрит что вообще за команда то была по ид.


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: SABROG от Июль 29, 2010, 12:24
Стандартный метод (http://thesmithfam.org/blog/2009/09/30/lock-free-multi-threading-in-qt/) вызвать слот из другого потока, который вышлет сигнал, когда данные или работа будет завершена. Тут только возникает проблема с контекстом локальных переменных, если их значения нужно восстановить после получения результата и продолжить некую логику зависящую от них и возвращенного значения (как это сделано в closure'ах).


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: JamS007 от Июль 29, 2010, 16:47
SABROG, спасибо, познавательная статейка. В принципе так и думал делать :)

Еще один вопрос: есть 2 потока. Пусть в первом из них будет динамически создана переменная, тоесть память возметься из кучи, а в самом потоке будет только указатель на нее. Сможет ли второй поток обратиться по переданному указателю к этой переменной, если поток 1 находиться в ожидании и не работает. Я имею ввиду, кокой из потоков в конце концов обработает обращение к памяти, тот что запрашивает переменную из памяти, или тот, что ее создал?

По другому можно сформульровать вопрос так: динамические переменные создаються адресном пространстве потока, или в общем? И если в общем, то можно ли к ним получить доступ из разных потоков?


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: SABROG от Июль 29, 2010, 16:55
В принципе через локальный QEventLoop можно симулировать сохранение локальных переменных и ожидание результатов из слота.


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: BRE от Июль 29, 2010, 16:56
По другому можно сформульровать вопрос так: динамические переменные создаються адресном пространстве потока, или в общем? И если в общем, то можно ли к ним получить доступ из разных потоков?
Все потоки работают в одном адресном пространстве.


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: Igors от Август 02, 2010, 13:43
По другому можно сформульровать вопрос так: динамические переменные создаються адресном пространстве потока, или в общем? И если в общем, то можно ли к ним получить доступ из разных потоков?
В общем, если "только чтение" то проблем никаких


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: Barmaglodd от Август 02, 2010, 14:17
В общем, если "только чтение" то проблем никаких
Угу, у вас все операции с памятью как транзакции в БД работают? Особенно интересно в контексте конструктора сложного объекта.


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: Igors от Август 02, 2010, 14:42
Угу, у вас все операции с памятью как транзакции в БД работают? Особенно интересно в контексте конструктора сложного объекта.
До чого тут транзакцii БД?  :)  Не понял Вашего вопроса, поясните на примере


Название: Re: Не блокирующий обмен данными между потоками
Отправлено: Barmaglodd от Август 02, 2010, 15:08
Я к тому, что переключение контекста может быть и в середине конструктора, но если создать объект, потом передать указатель и не трогать объект, то да проблем никаких. :)