Что я хочу сделать, так это то, что основной поток сначала пытается выполнить обычную отложенную отмену в рабочем потоке (выполняя код, который для моих целей является черным ящиком), а затем, если поток все еще работает после тайм-аута (pthread_timedjoin_np()
), я хочу сделать асинхронную отмену. У меня проблема в том, что pthread_setcanceltype()
предназначен только для вызывающего потока. Есть ли обходной путь или хак, который позволит мне это сделать? Я хочу избежать использования сигналов, поскольку, по крайней мере, в Linux кажется, что асинхронная отмена по-прежнему будет выполнять деструкторы C++ объектов потока, что важно для меня.
Изменить тип отмены pthread другого потока?
Ответы (1)
Есть несколько случаев, когда pthread_setcanceltype()
действительно должен выполнить отмену (см. исходный код ниже). Итак, это причина, почему нет pthread_setcanceltype_for_thread()
. Фактический тип отмены — это поле в структуре pthread, которое должно быть изменено атомарно.
__pthread_setcanceltype (type, oldtype)
int type;
int *oldtype;
{
volatile struct pthread *self;
self = THREAD_SELF;
int oldval = THREAD_GETMEM (self, cancelhandling);
while (1)
{
int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS
? oldval | CANCELTYPE_BITMASK
: oldval & ~CANCELTYPE_BITMASK);
/* Store the old value. */
if (oldtype != NULL)
*oldtype = ((oldval & CANCELTYPE_BITMASK)
? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED);
/* Update the cancel handling word. This has to be done
atomically since other bits could be modified as well. */
int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
oldval);
if (__builtin_expect (curval == oldval, 1))
{
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
{
THREAD_SETMEM (self, result, PTHREAD_CANCELED);
__do_cancel (); // HERE THE CANCELLING
}
break;
}
/* Prepare for the next round. */
oldval = curval;
}
return 0;
}
strong_alias (__pthread_setcanceltype, pthread_setcanceltype)
Если у вас есть большая потребность во внешнем изменении типа отмены, вы можете взломать библиотеку и установить поле напрямую.
PS: для NPTL (текущая реализация pthreads в glibc в Linux) самый простой способ увидеть, как получить struct pthread
из int pthread_t, это... pthread_join:
pthread_join (pthread_t threadid, thread_return)
{
struct pthread *pd = (struct pthread *) threadid;
person
osgx
schedule
06.07.2011
Проблема в том, что поле отмены находится не в pthread_t, которое определено как
typedef unsigned long int pthread_t;
, а в поле struct pthread
, которое находится в descr.h.
- person Display Name; 07.07.2011
[упс, я редактировал, но время истекло] pthread_t определяется как uint в pthreadtypes.h. Поле отмены находится в
struct pthread
, которое находится в descr.h. Я не понимаю, как я могу получить это из pthread_t. Код для pthread_cancel()
, который вы опубликовали, использует макрос THREAD_SELF, который читает из регистра (по-видимому, потому что он быстрее, чем обычное чтение из локального хранилища потока), но этот регистр будет указывать на конкретный поток, поэтому я не могу получить к нему доступ из другого . В любом случае я могу получить доступ к TLS другого потока или к другому обходному пути?
- person Display Name; 07.07.2011
Подсказка 1: память одинакова для обоих потоков. Подсказка 2: отладчик может получить доступ ко всем структурам потоков.
- person osgx; 07.07.2011
Самый простой способ увидеть, как pthread_t преобразуется в struct pthread, это ... pthread_join: pthread_join (pthread_t threadid, thread_return) { struct pthread *pd = (struct pthread *) threadid;. Возьми? %)
- person osgx; 07.07.2011
Что ж, это упрощает дело. :) Спасибо за помощь.
- person Display Name; 07.07.2011
Единственное, что нужно добавить на случай, если кто-то еще попытается это сделать: __do_cancel() — это функция, которая вызывается отменяемым потоком (она также использует THREAD_SELF), поэтому ее также следует изменить, чтобы установить бит выхода и вызвать раскрутку. функция для другого потока.
- person Display Name; 07.07.2011
do_cancel не может вызвать раскрутку другого потока. Таким образом, вы не можете изменить тип отмены другого потока на PTHREAD_CANCEL_ASYNCHRONOUS, если ожидается внешний запрос на отмену. (функция __pthread_unwind использует THREAD_SELF). Кроме того, вызов __pthread_unwind (объявленный с помощью
__attribute ((noreturn))
) не может вернуться к вызывающей стороне: /* NOTREACHED / / Нам лучше сюда не попадать. */ прервать ();
- person osgx; 07.07.2011
CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS требует установки CANCELED_BITMASK, а pthread_cancel устанавливает ее после отправки SIGCANCEL потоку. Если я выполню pthread_cancel, когда режим отложен, то pthread_timedjoin_np вернет ETIMEDOUT, что можно сказать о том, будет ли установлен CANCELED_BITMASK?
- person Display Name; 07.07.2011
@DisplayName, если вам удалось изменить тип другой темы, не могли бы вы рассказать мне, как это сделать? Я пытаюсь сделать то же самое, но если мне придется сделать это без изменения библиотеки, я не могу понять, как получить pthread-›cancelhanling, поскольку структура pthread взята из descr.h, а не из pthread.h. Поэтому, даже если у меня есть указатель на структуру, я не могу изменить ее атрибуты (обработка отмены)
- person mathworker; 31.12.2018