LINUX.ORG.RU

[Нити] Жизнь и смерть


0

0

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

Ответ на: комментарий от Pantserovik

Потому что thread можно перевести и как нить, и как поток. А по поводу контроля потоков могу посоветовать почитать Стивенса. У него очень хорошо разжевано про мьютексы, семафоры и т.п. А еще можно набрать man pthread<TAB> и посмотреть, какие функции есть для работы с потоками :)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от dave

Ну вот в отношении многозадачности «нить вычисления» звучит понятней чем «поток вычисления», и если «писать в поток» - тоже понятно. Помню как-то спросил про потоки и начали рассказывать не про потоки а про «потоки» :)

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Это смотря кто какую литературу читал. Мне привычнее результат pthread_create называть потоком, а результат fork - процессом.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от quasimoto

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

Pantserovik
()

Помимо надежности хочется чтобы код был простым и прозрачным, а не запутанным.

если бы это было возможно

p.s у меня многопоточные проги самые трудные и код там далеко не простой получается именно запутанный

osox
()
Ответ на: комментарий от Pantserovik

>> Мне привычнее результат pthread_create называть потоком, а результат

Во, согласен, испокон веков так было ;-)

Испокон веков «thread» называли «нитью». Но потом пришли переводчики микрософт с мозгами, сожранными дружественностью к пользователю.

tailgunner ★★★★★
()
Ответ на: комментарий от Pantserovik

>А что смешно? Заниматься банальным сексом со всякими низкоуровневыми функциями? Ну да, наверное ;-)

Когда я прошу поделится опытом, то это не значит, что я хочу чтобы мне указали на API.

pathfinder ★★★★
() автор топика

> Нити могут сами завершиться, а может потребоваться завершить их из другого потока.

Второго лучше не делать.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

osox
()
Ответ на: комментарий от Pantserovik

А что смешно? Заниматься банальным сексом со всякими низкоуровневыми функциями? Ну да, наверное ;-)

а там такие высокоуровневые написаны, да?

уж тогда

#pragma omp parallel 
//some stuff
shty ★★★★★
()
Ответ на: комментарий от tailgunner

>> Нити могут сами завершиться, а может потребоваться завершить их из другого потока.

Второго лучше не делать.

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

Принудительное завершение действительно лучше не делать. Но есть же мягкие способы завершить выполнение нити. Например если это позволяет логика, то нить может периодически поглядывать на некую переменную и исходя из её состояния он может завершить выполнение в удобный для неё момент времени. Но такой способ не лишен недостатков и требует некоторой осторожности. Можно ещё использовать pthread_cancel() с правильно настраиваемым атрибутом отмены. Но это можно сделать лишь в рамках pthread, да и от всех случаев не спасет.

Похоже, что серебряной пули нет. :(

pathfinder ★★★★
() автор топика
Ответ на: комментарий от pathfinder

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

Я называю это «нить завершается сама». Заодно она же и чистит за собой ресурсы.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Я называю это «нить завершается сама». Заодно она же и чистит за собой ресурсы.

Когда я говорил про завершение из другого потока я имел ввиду, что в другом потоке принимается решение о необходимости закрыть поток. Эта ситуация отличается от той, когда мы создали нить, отпустили её в вольное плавание и забыли про неё.

В общем согласен. Лучше всего когда нить может догадаться, что ей пора завершить работу. Хуже когда она может заснуть на неопределенный срок, например на вызове read(). Зачастую нити создаются лишь для того, чтобы использовать возможности блокирующего ввода/вывода. Как лучше поступать в таких ситуациях? Засыпать на чтении с таймаутом с помощью вызова poll() или как-то ещё? Как-то не очень красиво это будет выглядеть.

pathfinder ★★★★
() автор топика
Ответ на: комментарий от pathfinder

> Засыпать на чтении с таймаутом с помощью вызова poll() или как-то ещё?

Или посылать ей сигнал, а нити после EINTR проверять значение очереди запросов/переменной pleasequit.

tailgunner ★★★★★
()

Стараться свести взаимодействие между нитями к минимуму. Будет меньше головной боли. Если есть возможность - использовать готовые решения, где уже люди потратили время на отладку.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от shty

ну да, там все просто, переопределил виртуальную функцию, которая работать будет - и все.

Pantserovik
()
Ответ на: комментарий от Boy_from_Jungle

>..., чтобы не задавать больше таких провакационых вопросов.

Я сказанной фразы не понял.

pathfinder ★★★★
() автор топика
Ответ на: комментарий от tailgunner

я использую переменную:

master ()
{
  ctx->state = RUN;
  thread_create (slave, ctx);
  ...
  ctx->state = STOP;
  slave_wakeup ();/*вывести нить из блокированного состояния*/
  thread_join ();
}

slave (ctx)
{
  while (ctx->status == RUN) {
    ...
  }
}
но надо помнить о:

  • sem_wait в некоторых реализациях не прерывается сигналом,
  • компилятор и процессор меняют порядок выполнения команд, надо применять memory barriers для синхронизации нитей, Documentation/memory-barriers.txt
fopen ★★
()
Ответ на: комментарий от Pantserovik

почему потоки некоторые личности называют нитями.

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

Xenesz ★★★★
()
Ответ на: комментарий от fopen

> ctx->state = RUN;

...

ctx->state = STOP;

Вообще-то на x86 чтение/запись могут быть не атомарными.

компилятор и процессор меняют порядок выполнения команд, надо применять memory barriers для синхронизации нитей,

В юзерспейсе?

frey ★★
()
Ответ на: комментарий от tailgunner

Испокон веков «thread» называли «нитью». Но потом пришли переводчики микрософт с мозгами, сожранными дружественностью к пользователю.

Сказанное очень похоже на правду.

Из википедии (http://ru.wikipedia.org/wiki/Thread):

Критика терминологии

Перевод английского термина thread как «поток» в контексте, связанном с программированием, противоречит его же переводу «нить» в общеязыковом контексте, а также создает коллизии с термином stream («поток»).

По некоторым сведениям, этот неудачный перевод зародился во второй половине 1990-х годов в кругах, близких к российскому офису компании Microsoft, и занимавшихся переводом на русский язык англоязычной литературы издательства Microsoft Press.

Мне этот спор кажется бессмысленным. На сегодняшний день употребляются оба понятия.

pathfinder ★★★★
() автор топика
Ответ на: комментарий от frey

> Вообще-то на x86 чтение/запись могут быть не атомарными.

Да. Добавь в список: помнить о атомарности операций с этой переменной. Есть атомарные команды и посложнее чтения/записи.

компилятор и процессор меняют порядок выполнения команд, надо применять memory barriers для синхронизации нитей,

В юзерспейсе?

Да. Везде.

Переменную МОЖНО применять для межпроцессного взаимодействия, но НУЖНО понимать очень низкоуровневые детали.

Кто использует mutex_lock, тот не пьет шампанское.

fopen ★★
()
Ответ на: комментарий от Pantserovik

Ещё есть, например, задача нахождения макс потока(max flow).

anonymous
()
Ответ на: комментарий от osox

>разослать всем потокам подлежащим завершению сигналы чтоб они их приняли и сами заершились

Я надеюсь, речь идет не о pthread_kill?

linuxfan
()

>Надо быть уверенным что при этом всегда освобождаются ресурсы

Use C++ + RAII, Luke

и нет «висячих» нитей, race condition

Use brain, Luke

Помимо надежности хочется чтобы код был простым и прозрачным, а не запутанным.

Таким требованиям разве что «hello world» удовлетворяет. Сложные приложения есть и от них никуда не деться.

linuxfan
()
Ответ на: комментарий от linuxfan

речь о том чтоб не давать потоку подзатыльника грубо его завершая а послать такой сигнал который он увидит освободит все свои ресурсы и завершится сам

osox
()
Ответ на: комментарий от osox

А я под линукс, поэтому «послать сигнал» воспринял как буквальное руководство к действию.

linuxfan
()
Ответ на: комментарий от linuxfan

>> разослать всем потокам подлежащим завершению сигналы чтоб они их приняли и сами заершились

Я надеюсь, речь идет не о pthread_kill?

Именно о нем. Что-то не так?

tailgunner ★★★★★
()
Ответ на: комментарий от fopen

> компилятор и процессор меняют порядок выполнения команд, надо применять memory barriers для синхронизации нитей, Documentation/memory-barriers.txt

Господи, прости им, ибо не ведают, что творят...

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Именно о нем. Что-то не так?

man pthread_kill
NOTES
       Signal dispositions are process-wide: if a signal handler is installed, the handler will be invoked in the thread  thread,  but  if  the
       disposition of the signal is "stop", "continue", or "terminate", this action will affect the whole process.

Как по мне, так эту кривоту в многопоточных приложениях лучше просто не использовать.

linuxfan
()
Ответ на: комментарий от linuxfan

> but if the disposition of the signal is «stop», «continue», or «terminate»

Ну понятно, что не нужно посылать другой нити SIGKILL или SIGSTOP... но речь шла о прерывании длительной операции В/В и обработке EINTR.

tailgunner ★★★★★
()
Ответ на: комментарий от LamerOk

>Риальные потсаны делают свои мьютексы с гимнастками и гольфом на двоичных кодах целевой машины?

Они мьютексы не используют. Гимнастки, гольф и машины - это да. Это ж пацаны!

fopen ★★
()
Ответ на: комментарий от tailgunner

>> компилятор и процессор меняют порядок выполнения команд, надо применять memory barriers для синхронизации нитей, Documentation/memory-barriers.txt

Господи, прости им, ибо не ведают, что творят...

Ну, так просвяти их!

fopen ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.