LINUX.ORG.RU

как скрестить poll и pthread_mutex_lock

 , ,


0

2

велосипедю двухпоточный web-server на C. В одном потоке - poll по всем клиентам, во втором - доступ к БД. Нужно их как-то синхронизировать. Подскажите плз способ.

Есть такая штука как interrupts, в java это помогло бы, а на C?

Может, есть другие варианты?

Спасибо

UPD по сигналу от потока БД нужно прервать poll и запустить заново, с другими параметрами

★★★★★

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

по сигналу от потока БД нужно прервать poll

Делаешь специальный pipe, куда нить БД пишет байт (или что-то более осмысленное).

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

Есть такой вариант: 1) Тред, работающий с БД, делает pthread_kill (посылка сигнала треду) и посылает, например, SIGUSR1. 2) poll (как и многие другие системные вызовы) прерывается при получении сигнала 3) Тред, делающий poll, получает от poll значение -1 и errno=EINTR и анализирует, что нужно сделать.

dmitry_vk ★★★
()

Pipe либо eventfd как более быстрый частный случай (linux-specific).

gv
()

просто праздник возможностей! всем спасибо.

сам собирался писать по рецепту dmitry_vk (SIGUSR1), только вместо poll заюзать ppoll, самое оно. Но eventfd выглядит интересно, охота попробовать.

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

пока читаю man eventfd, gv, гигантское спасибо

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

сам собирался писать по рецепту dmitry_vk (SIGUSR1)

Большая ошибка.

eventfd выглядит интересно, охота попробовать.

Это и непереносимо, и излишне в данной задаче.

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

был бы рад увидеть мотивировку и того и другого

Ты сам-то свои решения мотивировал - хотя бы для себя?

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

Насчет непереносимости eventfd - что тут мотивировать? В man всё написано. Мотивировать использование pipe с сигнальным байтом? Это идиоматично и переносимо. Я бы еще понял, если бы ты реализовал waitable queue на eventfd, но, похоже, ты собрался вставить его прямо в poll.

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

pipe вариант неудобный, так как опасность блокировок на записи нужно решать

Если нужен не только Linux, можно использовать eventfd только как оптимизацию, а код написать так, чтобы он работал и с pipe.

Что-то вроде:

db_thread()
{
  while (1)
  {
    fds.add(db_fd, POLLIN);

    if (last_reported_counter < counter)
        fds.add(pipe_or_event_fd, POLLOUT);

    poll(fds);

    if (isset(db_fd)) {
       if (new_db_event)
          counter ++;
    }

    if (isset(pipe_or_event_fd)) {
        write(pipe_or_event_fd, 1);
        last_reported_counter ++;
    }
  }
}

Ну и вынести работу с pipe/eventfd в отдельный модуль/класс/etc.

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

был бы рад увидеть мотивировку и того и другого

Про сигналы: если использовать их в одном месте программы, то думать о них придется и во всех остальных тоже.

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

Я бы еще понял, если бы ты реализовал waitable queue на eventfd, но, похоже, ты собрался вставить его прямо в poll.

Why not? Зависит ведь от конкретной задачи.

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

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

ppoll маскирует/демаскирует нужные сигналы атомарно.

Насчет непереносимости eventfd - что тут мотивировать?

это очевидно. я просил объяснить, почему излишне

Мотивировать использование pipe с сигнальным байтом? Это идиоматично и переносимо.

переносимость мне в данном случае не нужна. идиоматичность? хз, не видел. в этом случае мне предпочтителен более высокий уровень абстракции eventfd.

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

Ты сам-то свои решения мотивировал - хотя бы для себя?

я не пойму, как ты умудрился ответить на мой пост вроде бы в тему, не читая его?

был бы рад увидеть мотивировку и того и другого

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

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

я просил объяснить, почему излишне

Потому что не дает ничего по сравнению с pipe.

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

ppoll маскирует/демаскирует нужные сигналы атомарно.

Ты точно прочитал то, на что ответил? Речь о том, что делать, когда сигнал приходит не во время poll.

я не пойму, как ты умудрился ответить на мой пост вроде бы в тему, не читая его?

Я внимательно прочел твой пост.

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

Потому что не дает ничего по сравнению с pipe

4.2, eventfd проще

Речь о том, что делать, когда сигнал приходит не во время poll.

не во время ppoll (с двумя «p», не с одной) сигнал заблокирован, естессно

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

Потому что не дает ничего по сравнению с pipe

4.2, eventfd проще

Чем? Те же read/write/poll.

не во время ppoll (с двумя «p», не с одной) сигнал заблокирован, естессно

Это потеря реактивности.

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

строчку в мане, гарантирующую отсутствие блокировки

Тут все просто, могу я показать :)

pipe(7)

A pipe has a limited capacity. If the pipe is full, then a write(2) will block or fail <...> Since Linux 2.6.11, the pipe capacity is 65536 bytes.

fcntl(2)

F_SETPIPE_SZ (int; since Linux 2.6.35)

Change the capacity of the pipe referred to by fd to be at least arg bytes.

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

eventfd проще

Чем? Те же read/write/poll.

уровень абстракции

Уровень абстракции не зависит от операций на объекте? Окей.

потеря реактивности

что это?

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

P.S. если man прав и ppoll в самом деле состоит из:

           sigprocmask(SIG_SETMASK, &sigmask, &origmask);
           ready = poll(&fds, nfds, timeout);
           sigprocmask(SIG_SETMASK, &origmask, NULL);

то ты блокируешь сигнал во всем процессе %)

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

ТС хочет отсутствия блокировки на неопределенное при записи.

pipe гарантирует неблокирующуюся запись до PIPE_BUF байт. Если программе нужно больше, у нее серьезные проблемы.

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

Уровень абстракции не зависит от операций на объекте? Окей

зависит и от операций, но не только от них, само собой. у eventfd абстракция в данном случае имхо повыше.

если man прав и ppoll в самом деле состоит из ...

да, странно. хотя, весь пак манов не особо учитывает pthreads. хз.

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

Если программе нужно больше, у нее серьезные проблемы.

Ну да. Серьезные проблемы у читателя, который не читает/читает медленнее. В случае pipe для корректной обработки этой ситуации писатель тоже должен использовать select/poll/etc, то есть его код усложняется.

Вот собственно разница между pipe и eventfd, вопрос переносимости — другой вопрос.

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

Уровень абстракции не зависит от операций на объекте? Окей

зависит и от операций, но не только от них, само собой. у eventfd абстракция в данном случае имхо повыше.

Реально выше был бы уровень абстракции очереди. Уровни абстракции eventfd и pipe совпадают.

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

Серьезные проблемы у читателя, который не читает/читает медленнее. В случае pipe для корректной обработки этой ситуации писатель тоже должен использовать select/poll/etc, то есть его код усложняется.

eventfd не избавляет от необходимости проверять эту ситуацию.

Вот собственно разница между pipe и eventfd

Ну да, а разница в накладных расходах ядра - это так, фигня.

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

разница в накладных расходах ядра

скорее, eventfd эффективней. Если, конечно, он не через pipe реализован, а напрямую.

eventfd не избавляет от необходимости проверять эту ситуацию.

куда дальше упрощать?

res = write(eventfd);
if(res == -1 && errno != EAGAIN) ошибка; else все_ок_флаг_и_так_установлен_если_че;

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

eventfd не избавляет от необходимости проверять эту ситуацию.

Избавляет от этой необходиомти писателя.

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

Вот собственно разница между pipe и eventfd

Ну да, а разница в накладных расходах ядра - это так, фигня.

С точки зрения использования.

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

скорее, eventfd эффективней

Смотря что понимать под «эффективностью».

if(res == -1 && errno != EAGAIN) ошибка; else все_ок_флаг_и_так_установлен_если_че;

Бугага.

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

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

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

а не нужно сигналить ошибку

А что тогда значило «ошибка» у тебя в псевдокоде?

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

Мде. Ну и ладно.

tailgunner ★★★★★
()

Чем вам не нравится полностью заполненный буфер pipe, можете объяснить? Ведь в этом случае ppoll просто сразу вернёт управление - читать то из pipe есть чего.
Т.е. достаточно писать в pipe один байт в неблокирующем режиме и не имеет значения, произошла действительно запись или нет.

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