Posix C write () и потокобезопасность - PullRequest
3 голосов
/ 04 января 2011

Существует способ сериализации C write(), чтобы я мог записывать байты в сокет, совместно используемые k-потоками, без потери данных?Я полагаю, что решение этой проблемы включает блокировку пространства пользователя, а как насчет масштабируемости?Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 04 января 2011

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

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

Даже если вашим потокам нужен ответ на их сообщения, они все равно могут заплатить за что-то подобное. Ваш поток обслуживания сокетов становится более сложным, потому что вам нужно будет сделать что-то вроде select () для сокета для чтения и записи, чтобы остановить его блокировку, и вам также потребуется способ сопоставления сообщений с ответы и способ информировать потоки о получении ответов.

0 голосов
/ 04 января 2011

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

Вы можете иметь такую ​​структуру:

typedef struct my_socket_data_st
{
int msg_id;
#ifdef __debug_build__
    int thread_id;
#endif
size_t data_size_in_bytes;
.... Followed by your data ....
} my_socket_data_t

Масштабируемость зависит от многих вещей, включая аппаратные ресурсы, на которых будет работать ваше приложение.Поскольку это сетевое приложение, вам также придется подумать о пропускной способности сети.Хотя нет (есть несколько, но я думаю, что вы можете пока игнорировать их для своего приложения) ограничения от ОС при отправке / получении данных через сокет, но вам придется подумать о том, чтобы сделать send синхронным или асинхроннымна основе вашего требования.Кроме того, поскольку вы берете блокировку, вам также придется подумать о перегрузке блокировки.Если блокировка недоступна для других потоков, это значительно снизит производительность.

0 голосов
/ 04 января 2011

Так как POSIX, по-видимому, не определяет гарантии атомарности при send (2), вам, вероятно, придется использовать мьютекс.Масштабируемость, конечно же, теряет популярность благодаря такой сериализации.

...