Вынуждение ожидающего потока вернуться в пользовательское пространство

Можно ли разбудить поток, ожидающий блокировку фьютекса? Я пытался использовать сигнальный механизм, но, похоже, он не работает. Есть ли другие подходы, которые я мог бы попробовать? Ниже я добавил пример, который может быть похож на то, чего я пытаюсь достичь.

  1. У меня есть поток A, который получает блокировку фьютекса "lockA" следующим образом: - ret = syscall(__NR_futex, &lockA, FUTEX_LOCK_PI, 1, 0, NULL, 0);

  2. У меня есть поток B, который пытается получить блокировку фьютекса «lockA» и блокируется в ядре, поскольку поток A получил блокировку. ret = syscall(__NR_futex, &lockA, FUTEX_LOCK_PI, 1, 0, NULL, 0);

  3. Если поток B получит блокировку A, другой поток, поток C, узнает об этом. Если поток B не получает блокировку, поток C хотел бы, чтобы поток B прекратил ожидание блокировки и сделал что-то другое.

Итак, в основном, на данный момент я пытаюсь выяснить, могу ли я заставить поток C «сигнализировать» потоку B, чтобы он больше не блокировался в ядре. Для этого я установил обработчик сигнала в потоке B следующим образом:

struct sigaction act;

act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_restorer = NULL;
sigaction(SIGSYS, &act, NULL);

...
...

void handler() {
  fprintf(stderr, "Inside the handler, outta the kernel\n");
}

Из потока C я пытаюсь отправить сигнал как: - pthread_kill(tid_of_B, SIGSYS);

Что я делаю не так? Можно ли вообще разбудить поток B? Если да, следует ли использовать другой подход?

[EDIT] Основываясь на комментарии ниже, я попытался проверить возвращаемое значение из pthread_kill и понял, что вызов не возвращается.


person Community    schedule 16.11.2015    source источник
comment
Теоретически, я думаю, отправка сигнала должна работать. Если вы делаете поток занятым ожиданием или sleep(), а затем отправляете сигнал, вызывается ли ваш обработчик?   -  person abligh    schedule 16.11.2015
comment
@ablight Спасибо за ваш ответ. Вы имеете в виду, что поток B должен спать?   -  person    schedule 16.11.2015
comment
Я бы рекомендовал не вызывать асинхронно-небезопасные функции в обработчике сигналов даже для отладки. Если вам действительно нужно протоколировать вызов вашего обработчика сигналов, write() to STDERR_FILENO.   -  person EOF    schedule 16.11.2015
comment
в общем, вызов syscall() не является хорошей идеей, так как базовые номера вызовов и список параметров могут меняться от одного обновления ОС к другому. Предлагайте всегда вызывать библиотечную функцию. в этом случае я думаю, что вызов mutex_lock() проще, понятнее и намного надежнее.   -  person user3629249    schedule 16.11.2015
comment
Какое значение возвращает вызов pthread_kill()?   -  person alk    schedule 16.11.2015
comment
@uki, похоже, вы не используете фьютексы по назначению (см. futex(7)). В частности, обычно вы делаете системный вызов как часть приобретения фьютекса только в случае, когда получение оспаривается. Поскольку это именно тот случай, когда вы хотите, чтобы поток B избегал блокировки, возможно, это признак того, что вы хотите вообще избежать этого системного вызова.   -  person John Bollinger    schedule 16.11.2015
comment
Кроме того, если вы выполняете системный вызов, вам следует использовать оболочку функции библиотеки futex().   -  person John Bollinger    schedule 16.11.2015
comment
@alk pthread_kill, похоже, не возвращается.   -  person    schedule 16.11.2015
comment
Рассматривали ли вы возможность использования обычного мьютекса pthreads вместо фьютекса? Как говорится в документации, голые фьютексы не предназначены для использования конечными пользователями в качестве простой в использовании абстракции. Я настоятельно рекомендую вам сделать работу вашей системы, во-первых, как можно проще. Только в том случае, если и где он недостаточно быстр, вы должны рассмотреть возможность использования фьютексов или других эзотерических методов для его ускорения. Даже в этом случае поиск лучшего алгоритма обычно дает больше преимуществ, чем настройка существующего для его ускорения.   -  person John Bollinger    schedule 16.11.2015
comment
@JohnBollinger Спасибо за ваш ответ, я буду иметь это в виду. Я делаю это просто как интеллектуальное упражнение   -  person    schedule 16.11.2015
comment
@uki Я имею в виду, попробуйте это со спящим потоком A, а не с вызовом futex(), чтобы проверить правильность вашего кода сигнала. Очевидно, это не то, что вы хотите сделать, но это может указать вам правильное направление (проблема, характерная для futex(), а не проблема с обработкой сигнала).   -  person abligh    schedule 16.11.2015


Ответы (1)


Несколько вещей.

Вы используете FUTEX_LOCK_PI, которого нет на странице руководства. Я только что просмотрел исходный код ядра и документ, и оказалось, что эта версия предназначена только для использования внутри самого ядра. Он используется для реализации «мьютекса PI» в качестве замены ядра spinlock.

Если вы используете futex, вы должны реализовать семантику данных в адресе, на который он указывает.

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

int mysem = 1;

void
lock(void)
{

    // atomic_dec returns new value
    while (1) {
        if (atomic_dec(&mysem) == 0)
            break;
        futex(&mysem,FUTEX_WAIT,...)
    }
}

void
unlock(void)
{

    // non_atomic_swap returns old value
    if (non_atomic_swap(&mysem,1) != 0)
        futex(&mysem,FUTEX_WAKE,...)
}
person Craig Estey    schedule 16.11.2015