Почему и когда я не должен убивать нить? - PullRequest
6 голосов
/ 11 ноября 2010

Я пишу многопоточный сервер сокетов, и мне нужно знать наверняка.

В статьях о потоках говорится, что я должен ждать возврата потока, а не убивать его.В некоторых случаях, однако, пользовательский поток, который я хочу удалить / забанить, не сможет вернуться должным образом (например, я начал отправлять большой блок данных, а send () блокирует поток в данный момент), поэтому я будунужно просто убить его.

Почему уничтожение потоковых функций опасно и когда они могут привести к сбою всего приложения?

Ответы [ 6 ]

18 голосов
/ 11 ноября 2010

Убить поток - значит остановить все выполнение именно там, где оно есть в данный момент.В частности, он не будет выполнять никаких деструкторов.Это означает, что сокеты и файлы не будут закрыты, динамически выделенная память не будет освобождена, мьютексы и семафоры не будут освобождены и т. Д. Уничтожение потока почти гарантированно приведет к утечкам ресурсов и взаимным блокировкам.

Таким образом, ваш вопрос как бы перевернут.Настоящий вопрос должен звучать так:

Когда и при каких условиях может уничтожить поток?

Итак, вы можете убить поток, когдавы убеждены, что утечки и взаимоблокировки не может произойти, не сейчас и не тогда, когда будет изменен код другого потока (таким образом, это практически невозможно гарантировать).


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

Более того, вы быстро поймете, что подход «поток на клиент»не масштабируется, так что вы измените свою архитектуру и в любом случае перепишете ее.

7 голосов
/ 11 ноября 2010

Уничтожение потока может привести к утечке ресурсов вашей программой, потому что поток не получил возможности очистить себя. Подумайте о закрытии дескриптора сокета, по которому отправляется поток. Это приведет к немедленному возвращению блокирующего send () с соответствующим кодом ошибки. Затем нить может очиститься и спокойно умереть.

4 голосов
/ 11 ноября 2010

Если вы тяжело убьете свой поток, он может утечь ресурсы.

Вы можете избежать этого, когда создаете ветку для поддержки отмены.

Не используйте блокирующие вызовы и не используйте блокирующие вызовы с таймаутом. Получать или отправлять данные небольшими порциями или асинхронно.

2 голосов
/ 11 ноября 2010

Вы действительно не хотите этого делать.

Если вы уничтожите поток, пока он содержит критический раздел, он не будет освобожден, что, вероятно, приведет к поломке всего приложения.Некоторые вызовы библиотеки C, такие как выделение памяти в куче, используют критические разделы, и если вам случится уничтожить ваш поток, пока он делает «новый», то вызов нового из любого места в вашей программе вызовет остановку этого потока.

Вы просто не может сделать это безопасно без действительно крайних мер, которые намного более ограничительны, чем просто сигнал нити прекратить себя.

2 голосов
/ 11 ноября 2010

В случае, когда поток заблокирован во вводе / выводе, вам действительно не нужно его уничтожать, вместо этого у вас есть выбор между неблокирующим вводом / выводом, таймаутами и закрытием сокета из другого потока.Любой из них разблокирует поток.

2 голосов
/ 11 ноября 2010

Есть много причин, но вот простая: есть только одна куча. Если поток выделяет НИЧЕГО в куче, и вы убиваете его, то все, что он выделил, существует до завершения процесса. Каждый поток получает свой собственный стек и, таким образом, МОЖЕТ быть освобожден (зависит от реализации), но вы ГАРАНТИРУЕТЕ утечки в кучу, не позволяя ему отключиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...