LINUX.ORG.RU

pthread_cancel не завершает поток.


0

0

Функция, обрабатывающая поток.

void *
servis_output (void * arg)
{
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
int sock_output = ((struct itemDT *)arg)->sock.output;
char buf[BUF_SIZE];
int n;
while (1)
{
pthread_testcancel();
n = read (0,buf,BUF_SIZE);
write(sock_output,buf,n);
}
return NULL;
}

pthread_cancel (pth) не может завершить поток. Не подскажите почему, либо другой способ как это сделать?

Дык, оно в pthread_testcancel() почти не висит; спит, наверное, на read(), а там нет cancellation point.

Либо pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS), либо селектом read разрулить.

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

>> спит, наверное, на read(), а там нет cancellation point

Согласно POSIX она (cancellation point) там (в read) должна быть. И лично у меня под линуксом (2.6) вполне нормально завершался поток, ждущий данных из сокета на вызове read.

Deleted
()

2ryukzak: Вы под какой операционной системой тестируете?

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

> Согласно POSIX она (cancellation point) там (в read) должна быть.

Ну, вообще говоря, я не совсем понимаю такую логику... А можно ссылку? То есть, я не спец тут, просто интересно... Согласно POSIX, pthread cancellation points прописаны довольно чётко:

pthread_join() pthread_cond_wait() pthread_cond_timedwait() pthread_testcancel() sem_wait() sigwait()

а про не-pthread функции как-то ничего не сказано, вроде...

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

>> Ну, вообще говоря, я не совсем понимаю такую логику...

А иначе бы потоки, которые где-то блокируются (read/poll/wait/sleep/etc.) просто не возможно было бы валидно завершить извне. И существование функции pthread_cancel стало бы почти бессмысленным.

>> А можно ссылку?


http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html

Cancellation Points
Cancellation points shall occur when a thread is executing the following functions:

accept()
aio_suspend()
clock_nanosleep()
close()
connect()
creat()
fcntl()2
fdatasync()
fsync()
getmsg()
getpmsg()
lockf()
mq_receive()
mq_send()
mq_timedreceive()
mq_timedsend()
msgrcv()
msgsnd()
msync()
nanosleep()
open()
pause()
poll()
pread()
pselect()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_join()
pthread_testcancel()
putmsg()
putpmsg()
pwrite()
read()
readv()
recv()
recvfrom()
recvmsg()
select()
sem_timedwait()
sem_wait()
send()
sendmsg()
sendto()
sigpause()
sigsuspend()
sigtimedwait()
sigwait()
sigwaitinfo()
sleep()
system()
tcdrain()
usleep()
wait()
waitid()
waitpid()
write()
writev()

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

Ok, thanks. Слава богу, Open Group Base Specifications еще пока не официальный стандарт...

IMHO -- полный бред! Если я жду на read'е что-то из канала, и меня в этот момент беззастенчиво убивают -- не есть гут, однако...

> А иначе бы потоки, которые где-то блокируются (read/poll/wait/sleep/etc.) просто не возможно было бы валидно завершить извне.

Дык, типа -- для таких случаев люди и придумали PTHREAD_CANCEL_ASYNCHRONOUS атрибут... Никогда его не использовать -- лучшее решение, ИМХО, но уж если приспичило -- ССЗБ!

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

> Ok, thanks. Слава богу, Open Group Base Specifications еще пока не официальный стандарт...

ммм... простите за невежество - а что это, если не стандарт :-?

> IMHO -- полный бред! Если я жду на read'е что-то из канала, и меня в этот момент беззастенчиво убивают -- не есть гут, однако...

почему собственно?

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от Die-Hard

> IMHO -- полный бред!

Сам такой! На пальцах, отмена потока проверяется каждый раз, когда поток совершает системный вызов. Вроде бы дефакто стандарт.

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

> ...отмена потока проверяется каждый раз, когда поток совершает системный вызов. Вроде бы дефакто стандарт.

Отнюдь! Посмотри на дискуссию вокруг сигналов -- имеют ли право они рвать системные вызовы, и что тут хорошо, а что -- плохо...

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

>> IMHO -- полный бред! Если я жду на read'е что-то из канала, и меня в этот момент беззастенчиво убивают -- не есть гут, однако...

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

>> Дык, типа -- для таких случаев люди и придумали PTHREAD_CANCEL_ASYNCHRONOUS атрибут...

А если поток в данный момент не на получении "застрял", а на обработке пакета? В этом случае при асинхронном завершении поток может убиццо в совершенно неожиданном месте. В результате побьются какие-нибудь глобальные данные программы.

>> Никогда его не использовать -- лучшее решение, ИМХО, но уж если приспичило -- ССЗБ!

Вот именно, что использовать его надо только в очень крайних случаях =).

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

> ...простите за невежество - а что это, если не стандарт :-?

Ну, в общем, почти стандарт...

> >IMHO -- полный бред! Если я жду на read'е что-то из канала, и меня в этот момент беззастенчиво убивают -- не есть гут, однако...

> почему собственно?

Потому, что я не смогу обработать исключение.

Да, конечно, я могу всякую бяку перехватить -- но эта бякя находится на другом логическом уровне. Я от read() жду нормального (позиксного) возврата ошибки и переменной errno. И не надо говорить, что это все "устарело" -- оно всё вполне нормально работает. И программы, написанные 20 лет назад, все еще актуальны.

Die-Hard ★★★★★
()
Ответ на: комментарий от Deleted

> Допустим есть поток, единственная задача которого - непрерывное получение UDP-пакетов и складывание их куда-нибудь. Как вы предлагаете его завершить из основного потока программы. Например когда пользователь захотел её закрыть.

Внутренний протокол (+, может быть, select() ), очевидно!

"Папа" шлет нужный пакет (возможно, по параллельному каналу, завязанному на select() ), и "дочка" аккуратно совершает самоубийство -- ИМХО единственный "разумный" вариант...

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

>> Ну, в общем, почти стандарт...

Изначально вроде бы про POSIX шла речь? Или я неправильно понял? По моей ссылке - кусок из IEEE 1003.1. А IEEE 1003.1 это насколько я знаю и есть POSIX.1.

Или я таки где-то ошибаюсь?

Deleted
()
Ответ на: комментарий от Die-Hard

>> Внутренний протокол (+, может быть, select() ), очевидно!

>> "Папа" шлет нужный пакет (возможно, по параллельному каналу, завязанному на select() ), и "дочка" аккуратно совершает самоубийство -- ИМХО единственный "разумный" вариант...

Да, что-то я не подумал, так тоже можно сделать. В VLC именно так плагины убиваются.

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

А как быть с вызовами, которые не с файловыми дескриптораи работают? Например wait? Или вообще sleep/nanosleep?

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

> А как быть с вызовами, которые не с файловыми дескриптораи работают? Например wait? Или вообще sleep/nanosleep?

Ну, вообще говоря, я, возможно, слишком "старой закалки", и меня не шибко надо слушать... :-)

Идея в том, что "убивать" любые системные вызовы _всегда_ следует соответствующими партнерами, иначе просто логика программы буксует...

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

IMHO
проверка на каждом сисколе
это потеря производительности
которая для меня например кажеться
совершенно дурацкой

в софте который я пишу и проектирую
очень редко возникала необходимость убить тред
и даже если возникала то решалась
переодической проверкой типа if (must_die == 1) pthread_exit

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

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

2 mironov_ivan Mac OS X 10.4.11 (вот и наткнулся на её персональные

Относительно PTHREAD_CANCEL_ASYNCHRONOUS - увы тоже успеха не принесла.

> случаи же когда надо убить поток

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

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

За ссылку на select спасибо. Буду учиться дальше.

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

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

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

// wbr

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

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

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

ryukzak
() автор топика
Ответ на: комментарий от Die-Hard

>> Ну, что я могу сказать?

>> +1! :-)

Блин, вы мне прямо открыли глаза 8). Не подскажите что почитать по теме (дизайн моногопоточный приложений, IO и т.п. в этом направлении)?

Кстати отвечая на свой вопрос про прерывание sleep: я как-то не подумал что его можно заменить на select/poll и задача сведётся к убиению процесса, ждущего данные на дескрипторе.

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

> Блин, вы мне прямо открыли глаза 8). Не подскажите что почитать по теме (дизайн моногопоточный приложений, IO и т.п. в этом направлении)?

POSA1, POSA2

http://www.cse.wustl.edu/~schmidt/POSA/

все есть в emule.

// wbr

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

> проверка на каждом сисколе > это потеря производительности > которая для меня например кажеться > совершенно дурацкой

Сразу видно - человек разрабатывает оси, и всякие там юниксы и посиксы пишут идиоты, которым совсем невдомек, что они делают дурацкие и медленные вещи.

> в софте который я пишу и проектирую > очень редко возникала необходимость убить тред > и даже если возникала то решалась > переодической проверкой типа if (must_die == 1) pthread_exit

Во-первых, убить поток и завершить его это разные вещи. Вы, судя по примеру кода, явно не понимаете разницы. Так как у вас - его завершение.

Хотя, для архитекторов хэлоу-вордов такое простительно. Про орфографию и пунктуацию я промолчу.

> случаи же когда надо убить поток > висящий на read это прямое свиделельство > кривого дизайна, и причина потенциальных > сложно вылавливаемых багов

Как бы будете обрабатывать разные тайм-ауты при чтении файлов? (Подсказка: сетевые фс, битые компакты и тд, где много попыток повторного чтения и возможно длинное ожидание перед оканчинием операции).

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

> Отнюдь! Посмотри на дискуссию вокруг сигналов -- имеют ли право они рвать системные вызовы, и что тут хорошо, а что -- плохо...

Кружок юных писаталей ОС? Я ничего против обсуждения идей не имею, напротив. Но тут разговор про текущую реализацию и, возможно, про легаси .

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