LINUX.ORG.RU

Wait_event в userspace или ожидание события

 , ,


0

1

Есть задача. Смысл заключается в том чтобы просто ожидать(заблокировать поток пока переменная станет не 0).

Есть тупое решение. Предположим, что есть переменная (или указатель), меняющаяся извне - а:

while(!a){
    usleep(1000);
}

Но оно грузит процессор. В kernel space есть хорошая блокирующая функция wait_event(wq, a != 0), которая хорошо работает. Но использовать ее в юзере нельзя(или можно? как?). Так вот, гугление не принесло толка. Интересует ест ли аналогичная функция в юзерспейс или какой-то, метод реальзующий данный функционал.

Спасибо.


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

Нет. Для разблокировки по condition variable нужно вызывать метод notify_all. По сути при использовании все равно нужно опрашивать переменную чтобы вызвать метод. Это не ответ на вопрос.

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

В смысле? Тот, кто ждёт, дёргает wait() (если брать std::condition_variable) и больше не грузит проц, пока не проснётся, тот, кого ждут, дёргает notify_[all,one](), когда будет готов. Ну или я не понимаю задачи до конца

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

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

bool wait(time_t timeout); //тред встает в ожидание с таймаутом

void signal(); //другой тред сигналит, и будит того кто в ожидании стоит

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

Тоже мимо. Каким образом семафор узнает о изменении переменной? Представим,что эта переменная - указатель на общую память. А другой процесс взял и изменил а[0] с 0 на 1. wait_event как-то узнает. Я хз как, но это работает только в kernel space.

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

ну кто-то же меняет значение, вот пусть и дернет.

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

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

Сейчас я объясню как я делал в предыдущей задаче. Я создал символьное устройство. При чтении его у меня вызывался wait_event_interruptible(wq, flag !=0). А потом приходило прерывание, которое делало flag = 1; Но при этом никаких notify и прочего оно не делало, просто меняло состояние переменной.

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

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

а ты как хотел? ты посмотри, как wait_event в кернеле реализован. чудес-то не бывает.

то, что ты хочешь - это conditional variable. что за проблема дёрнуть сигнал при изменении?

Iron_Bug ★★★★ ()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от olelookoe

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

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

Тоже мимо. Каким образом семафор узнает о изменении переменной? Представим,что эта переменная - указатель на общую память. А другой процесс взял и изменил а[0] с 0 на 1. wait_event как-то узнает. Я хз как, но это работает только в kernel space.

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

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

так ты заюзай conditional variable и он будет спать, пока не дёрнут сигнал. а потом будешь проверять свою переменную.

сигнал генерит тот, кто меняет переменную. ну или ловить какие-то изменения от харда. обычно делают какой-то select или epoll на дескрипторы.

Iron_Bug ★★★★ ()
Последнее исправление: Iron_Bug (всего исправлений: 2)

так понимаю, что требуется перенести часть программы из kernel в userspace. Для уведомления от ядра есть select и poll с вариациями, которые д.б. реализованы в модуле ядра (ну или у обькта ядра - блока памяти и т.п. д.б. дескриптор) И к которым нужно обращаться из US. В качестве оберток над ними есть библиотеки libev, libevent и тд.

zudwa ()

В kernel space есть хорошая блокирующая функция wait_event(wq, a != 0)

а каким образом вообще возможно тут следить на состоянием переменной а, если компилятор С просто вычислит выражение a!=0, и сунет его как параметр в функцию в виде 0 или 1.

если конечно это не волшебный макрос какой-то…что заворачивает a!=0 в функцию и вызывает ее. но вызывать он ее будет все равно по сигналу какому-то, а не по изменению самой переменной.

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

При чтении его у меня вызывался wait_event_interruptible(wq, flag !=0).

А ты посмотри во что wait_event_interruptible разворачивается - там в цикле ожидание события + выход по условию. То же самое что с condition variable. По другому не бывает в принципе.

Проблемы дернуть нет. Как отследить изменение? Опрос в цикле грузит проц.Даже со слипами.

sleep и ожидание события - совершенно разные вещи. Как отследить тебе сказали.

slovazap ★★★★★ ()

я позырил в этот wait_event_interruptible. не следит он сам за изменением переменной. как я и думал, тот что переменную меняет, сигналит на это событие, тогда проверяется данное условие, и если оно тру, то ожидающий тред пробуждается.

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

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

Вот в том и проблема, что ждуп просто переменную. Она не умеет ничего дергать.

А я хочу контейнер, позволяющий вставку/удаление и доступ по индексу за O(1). Мы с тобой примерно в равном положении.

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 1)

Можно использовать hardware watchpoint. Через ptrace это можно сделать

http://www.secretmango.com/jimb/Whitepapers/ptrace/ptrace.html там пример есть

The following example is a program that implements a watchpoint on a memory location using ptrace(2) (assuming that the target system does not have an intrinsic watchpoint functionality... more on this further down). It will tell you the exact address of the instruction that changed the memory location supplied.

Но это те еще костыли

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от zudwa

так понимаю, что требуется перенести часть программы из kernel в userspace. Для уведомления от ядра есть select и poll с вариациями, которые д.б. реализованы в модуле ядра (ну или у обькта ядра - блока памяти и т.п. д.б. дескриптор) И к которым нужно обращаться из US. В качестве оберток над ними есть библиотеки libev, libevent и тд.

Вот здесь правильный ответ зарыт.
Т.е. ты поймал событие в kernel space, теперь нужно пробросить его в user space средствами системных вызовов. Что использовать конкретно, зависит от задачи. char device + poll, наверное, самый очевидный и универсальный ответ.
Есть и другие способы, netlink, тупо блокирующий read, гуглить что-то вроде «kernel and user space interaction linux», например https://pothos.github.io/papers/linux_userspace_kernel_interaction.pdf

Tayler ★★ ()
Последнее исправление: Tayler (всего исправлений: 1)

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

pon4ik ★★★★★ ()

да, кстати

В kernel space есть хорошая блокирующая функция wait_event(wq, a != 0), которая хорошо работает

define «хорошо работает», иначе эта тема - просто переливание из пустого в порожнее. Про все основные способы тут уже написали. Может, в твоем софте это место вообще не является бутылочным горлышком, тогда зачем что-то придумывать?

Lrrr ()

Смысл заключается в том чтобы просто ожидать(заблокировать поток пока переменная станет не 0). Есть тупое решение.

Это тупое решение можно сделать чуть умнее, например, с помощью exponential backoff.

ест ли аналогичная функция в юзерспейс

Без ядра усыпить поток нельзя.

есть переменная (или указатель), меняющаяся извне - а

Если переменная (или указатель) не atomic, то приведённый код может привести к UB.

Laz ★★★★ ()

Смысл заключается в том чтобы просто ожидать(заблокировать поток пока переменная станет не 0).

есть два исполнителя - желательно «порт» отображённый в бито-нибло-байто-слово в пространстве - ось которая машинерит отображение сиего точка в событие для (в частности) твоего «потока»

в чём у тебя затруднение то?

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

Ты про шаренную память через shm_open? Так просто poll/select повесь и жди себе, когда данные появятся. Когда данные появились, дёргаешь notify_[one,all], и всё

XMs ★★★★★ ()