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