В вашем коде есть несколько проблем ... вы создаете поток на входящем соединении и передаете всем созданным потокам ссылку (ту же ссылку) на переменную, в которой вы сохранили дескриптор сокета.Это заставит все потоки использовать одну и ту же переменную для хранения всех дескрипторов сокетов, которые вы получите из подстановочного знака.Вероятно, вы думаете, хорошо, я делаю копию только при запуске потока, так что этого не произойдет , но подумайте, что два соединения, которые приходят почти одновременно, поток main()
работает и обрабатывает оба.Затем первый и второй потоки планируются, и оба получают одинаковый сохраненный дескриптор (второй), и первое соединение просачивается.
Другое дело, что хотя эта переменная является локальной для главной, он перестанет существовать, как только main()
вернется (что не конец программы, если потоки должны выжить после main()
return
), но, как вы находитесь в бесконечном цикле (вы, вероятно,не знаю, но единственное средство для server_socket
, чтобы сообщить об ошибке, - это если вы уничтожаете (close()
it) в потоке или отбрасываете интерфейс, к которому он подключен.) Это может привести к SIGSEGV
trap.
Вы можете свободно передавать значение int
, приведенное к (void *)
, без проблем, так как функция тела потока преобразует его обратно в int
перед использованием, что вообще сводит к нулю, так как типы указателей обычно больше по размеру (или равны, но не меньше), чем int
.В любом случае, это строго неопределенное поведение , но, вероятно, это сработает (поскольку унаследованное программное обеспечение полно таких преобразований, поэтому все компиляторы обычно реализуют, чтобы попытаться соблюдать это). Правильный способ сделать это - объявитьstruct
информации, передаваемой потоку при запуске и возвращающемся из него.Затем вы можете хранить на нем все, что захотите, но подумайте, что, поскольку у вас есть динамическое количество потоков, вам нужно динамически распределить структуры.
В отношении использования client_counter
переменная, единственная нить, касающаяся этой переменной, это та, в которой выполняется код main()
.Это создает большую проблему, чем риск, представленный выше, два обновления в быстрой последовательности могут заставить оба потока обновлять значения в main после того, как main произведет оба обновления.
Другая проблема заключается в том, что вам нужно объявить это volatile
, поскольку код потока не будет предполагать, что он изменяется только между доступами и, вероятно, будет кэшировать его как переменную регистра.
Сообщения, передаваемые между main()
и различными полученными вами потоками, могут быть реализованы.двумя способами.Это является причиной того, что процедуры получают void *
на входе и возвращают void *
при возврате:
Первый использует динамические struct
локальных данных (malloc()
ed, переданный из main()
в поток и обратно при завершении (когда вы присоединяете поток к основному). Этот способ позволяет вам собирать информацию о результате из потока в main, а затем вам нужно free(3)
structв основном. Структура используется как коммуникационное сообщение между потоком и основной подпрограммой в обоих направлениях, и вы можете хранить там любую информацию, которую вам нужно передать или вернуть обратно. После завершения потока вы можете free()
структура в основном (не делайте этого в потоке, поскольку он должен пережить свою смерть)
Второе больше не требует связи с main()
, и потоки должны освободить структурупосле его завершения. Это проще и более адекватно вашему примеру. Таким образом, вы можете уничтожить структуру в потоке или в основном, но только если вы уже присоединились ки уверены, что структура не будет использоваться им.