Я работал над многопоточным сервером сокетов для Linux, и я пробую разные способы мультиплексирования ввода / вывода, чтобы увидеть, какой из них работает лучше всего.
У меня уже есть кодэто создает общий epoll / socket - с включенным EPOLLONESHOT - и каждый поток извлекает события из этого и затем перезагружает EPOLLONESHOT на fd после обработки.
(«Обработка» в данном случае означает чтение доEAGAIN / EWOULDBLOCK, а затем отправляю простой ответ. По сути, я использую «ab» для проверки этого, поэтому он отправляет HTTP-запрос GET и отправляет обратно HTTP «200 OK».)
НоЯ хотел попробовать SO_REUSEPORT.Таким образом, каждый поток имеет свой собственный epoll / socket, связанный с одним и тем же портом.По сути, каждый поток - это свой собственный «мини-сервер», и мы позволяем ядру распределять нагрузку между ними.
Я делаю accept (), получаю fd для входящего соединения, поэтому я добавляю это кEpoll.Как только обработка завершена на этом fd, я, естественно, вызываю close (), чтобы завершить диалог.
Но это, кажется, периодически отбрасывает входящие подтверждения (и "периодически" я имею в виду, что это ведет себя как состояние гонки - иногдаработает, иногда нет, случайным образом).
Читая об этом, очевидно, есть известная ошибка, что может быть условие гонки между accept () и close (), так как close () вызываетперебалансировка вещей и очередь приема просто сбрасываются, поэтому они сбрасываются.
Я пытаюсь найти способ обойти эту проблему.
Одна идея, которая у меня была, была разделитьпринимает из очереди обработки epoll, так что закрытие fd в epoll не может стереть принятие в этой очереди.
Но это не работает логически, так как у меня не может быть потока, оба блокаon accept () и блокировать epoll_wait () одновременно.Чтобы правильно мультиплексировать, мы должны блокировать все события.
Я понял, что столько «мини-серверов», сколько и ядер, и каждый из них привязан к ядру.Таким образом, они действительно работают бок о бок, без переключателей контекста.
Это означает, что хотя я мог бы порождать новый поток для обработки нового входящего fd - и оставить основной поток, чтобы просто принять ()в цикле - тогда это несколько противоречит цели закрепления процессоров, и вся идея мультиплексирования состоит в том, чтобы избавиться от вещи «один поток на соединение».
Я искал исходный код для сервера SO_REUSEPORTЧтобы узнать, как другие могут справиться с этим, но все, что я смог найти, это простая демонстрация, которая не была многопоточной / многоядерной.
Кто-нибудь знает, как я могу решить эту проблему, чтобы многопоточный сервер сокетов SO_REUSEPORT действительно работал?