Я пишу POSIX-совместимый многопоточный сервер на языке c / c ++, который должен иметь возможность принимать, читать и записывать большое количество соединений асинхронно.На сервере есть несколько рабочих потоков, которые выполняют задачи и иногда (и непредсказуемо) помещают в очередь данные для записи в сокеты.Данные также иногда (и непредсказуемо) записываются клиентами в сокеты, поэтому сервер также должен читать асинхронно.Один очевидный способ сделать это - дать каждому соединению поток, который читает и пишет из / в его сокет;однако это уродливо, поскольку каждое соединение может сохраняться в течение длительного времени, и поэтому серверу, возможно, придется хранить сотни или тысячи потоков только для отслеживания соединений.
Лучшим подходом было бы иметь один потокэто обрабатывало все сообщения, используя функции select () / pselect ().Т.е. один поток ожидает на любом сокете, чтобы быть доступным для чтения, затем порождает задание для обработки ввода, который будет обрабатываться пулом других потоков, когда вход будет доступен.Всякий раз, когда другие рабочие потоки производят вывод для соединения, оно ставится в очередь, и коммуникационный поток ожидает записи этого сокета, прежде чем записать его.
Проблема в том, что коммуникационный поток может ожидать вФункция select () или pselect (), когда выходные данные поставлены в очередь рабочими потоками сервера.Возможно, что если в течение нескольких секунд или минут вход не поступит, блок вывода в очереди будет просто ждать завершения коммуникационного потока select () ing.Однако этого не должно происходить - данные должны быть записаны как можно скорее.
Прямо сейчас я вижу пару решений для этого, которые поточнобезопасны.Во-первых, коммуникационный поток должен быть занят - ждать ввода и обновлять список сокетов, которые он ожидает для записи каждую десятую секунды или около того.Это не оптимально, поскольку включает в себя ожидание, но оно будет работать.Другой вариант - использовать pselect () и отправлять сигнал USR1 (или что-то эквивалентное) всякий раз, когда новый вывод помещается в очередь, что позволяет коммуникационному потоку немедленно обновлять список сокетов, в которых он ожидает состояния записи.Я предпочитаю последнее здесь, но все же не люблю использовать сигнал для чего-то, что должно быть условием (pthread_cond_t).Еще один вариант - включить в список файловых дескрипторов, которых ожидает select (), фиктивный файл, в который мы записываем один байт всякий раз, когда требуется добавить сокет в доступный для записи fd_set для select ();это разбудит сервер связи, потому что этот конкретный фиктивный файл будет доступен для чтения, что позволит коммуникационному потоку немедленно обновить свой доступный для записи файл fd_set.
Я чувствую, что второй подход (с сигналом) - это«самый правильный» способ программирования сервера, но мне любопытно, если кто-нибудь знает, какой из вышеперечисленных является наиболее эффективным, вообще говоря, вызовет ли любой из вышеперечисленных условий гонки, о которых я не знаю, или еслиКто-нибудь знает более общее решение этой проблемы.Что мне действительно нужно, так это функция pthread_cond_wait_and_select (), которая позволяет потоку связи ожидать как изменения сокетов, так и сигнала от условия.
Заранее спасибо.