LINUX.ORG.RU

Программа зависает на pthread_cancel()


0

2
код прибивания нитей
    shutdown(_cx_socket[i], 2);
    _cx_socket[i] = 0;
    printf("[A]\n");
    pthread_cancel(_cx_pthread[i]);
    printf("[B]\n");
....
здесь нити порождаются:
      pthread_create(&(_cx_pthread[i]), NULL, funcClientWatch, &(_cx_index[i]));

В цикле по i вызывается кусок "прибивания" нитей.
В частности, выполняется pthread_cancel().

Однако, оно зависает, выдав:
[A]
[B]
[A]
<тут висит>

По какой причине это может быть?

★★★★★

Убираю строку с pthread_cancel() - программа завершается (вызов «прибивания» у меня на signal(SIGINT) поставлен).

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

> а если без PTHREAD_CANCEL_DEFERRED?

Все-равно висит.

Это наблюдается только под FreeBSD - под линукс этот код завершается нормально.

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

shutdown(_cx_socket[i], 2);
...
pthread_cancel(_cx_pthread[i]);



Где гарантия, что сокет еще не используется потоком?

И да, ман про то, как рабоает pthread_cancel

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

Где гарантия, что сокет еще не используется потоком?


Мне это без разницы. Пользователем дан приказ - прибить. Прибиваю.

И да, ман про то, как рабоает pthread_cancel


А что не так в мане? По нему, все должно прибивать (см. 1,2,3).

DESCRIPTION
       The  pthread_cancel()  function  sends  a  cancellation request to the thread thread.  Whether and when the target thread reacts to the cancellation
       request depends on two attributes that are under the control of that thread: its cancelability state and type.

       A thread's cancelability state, determined by pthread_setcancelstate(3), can be enabled (the default for new threads) or disabled.  If a thread  has
       disabled cancellation, then a cancellation request remains queued until the thread enables cancellation.  If a thread has enabled cancellation, then
       its cancelability type determines when cancellation occurs.

       A thread's cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new  threads).   Asyn‐
       chronous  cancelability  means  that the thread can be canceled at any time (usually immediately, but the system does not guarantee this).  Deferred
       cancelability means that cancellation will be delayed until the thread next calls a function that is a cancellation point.  A list of functions that
       are or may be cancellation points is provided in pthreads(7).

       When a cancellation requested is acted on, the following steps occur for thread (in this order):

       1. Cancellation clean-up handlers are popped (in the reverse of the order in which they were pushed) and called.  (See pthread_cleanup_push(3).)

       2. Thread-specific data destructors are called, in an unspecified order.  (See pthread_key_create(3).)

       3. The thread is terminated.  (See pthread_exit(3).)

       The  above  steps  happen  asynchronously with respect to the pthread_cancel() call; the return status of pthread_cancel() merely informs the caller
       whether the cancellation request was successfully queued.

       After a canceled thread has terminated, a join with that thread using pthread_join(3) obtains PTHREAD_CANCELED as the thread's exit status.   (Join‐
       ing with a thread is the only way to know that cancellation has completed.)

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

> Мне это без разницы. Пользователем дан приказ

Так я не понял, кто программу пишет? Ты или пользователь?

А что не так в мане?


Да в мане-то всё в порядке.

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

> Так я не понял, кто программу пишет? Ты или пользователь?

Я просто не могу понять - в чем проблема, если я закрою открытые сокеты?
Или ты имеешь ввиду, что recv/send/shutdown надо обрамлять mutex'ами?

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

Причина явно не в pthread_cancel так как он просто регистрирует запрос на отмену потока.
Вероятно баг где-то в другом месте, может что-то корраптится.
На чем висит поток? Что strace говорит?

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

а если без PTHREAD_CANCEL_DEFERRED?

Она по дефолту ставится и это правильно.
Как известно использовать PTHREAD_CANCEL_ASYNCHRONOUS крайне опасно.

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

> На чем висит поток? Что strace говорит?

Не знаю. Посмотреть затруднительно. У меня под FreeBSD strace не установлен, в пакетах его нет, порты не поставлены, инета нету.

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

Поток может быть прерван только в точке прерывания (cancellation point). Этими точками являются некоторые (не все) системные вызовы. Системный вызов pthread_testcancel() должен быть точкой прерывания в любой системе.

iliyap ★★★★★
()

нить надо не прибивать, а завершать, перепиши без pthread_cancel

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

Не заметил что речь про фрю. Там вроде есть не совсем работающий порт strace но только под x86. В любом случае нативные аналоги должны помочь, например ktrace/kdump.

Здесь не похоже что не достигается cancelation point в другом потоке.
Даже если в теле потока вообще нет такой точки, поток выполняющий pthread_cancel не должен зависать.
Из-за того что всего кода мы не видим сложно сказать вызывается ли printf после pthread_cancel или нет (возможно и вызывается но проблема в буферизации вывода если он не line-buffered).

Или же до него не доходит или зависание происходит на нем. Такое вполне может быть если есть баг портящий память.

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

> Такое вполне может быть если есть баг портящий память.

Такое практически исключено. Причина - более тонкая, как мне кажется.

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

Такое практически исключено. Причина - более тонкая, как мне кажется.


Это очень даже возможно когда портится память выделенная под примитивы синхронизации например. Я неоднократно с таким сталкивался (правда под Linux).
Хотя я и не утверждаю что причина точно в этом.

Самый лучший вариант для автора - попробовать вырезать из программы все ненужное (но чтобы проблема осталась) и запостить код здесь.
Лично у меня есть несколько VM с FreeBSD от 7 до CURRENT и если что я могу воспроизвести проблему там и посмотреть в чем дело не гадая.

Часто бывает что когда делаешь из программы маленький пример для демонстрации бага, сам при этом находишь ошибку :)

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