LINUX.ORG.RU

POSIX signals и треды

 


0

3

Привет, аналитеги!

Вот tailgunner сказал мне, что мой профайлер, раз не поддерживает работу с тредами, то он не такой супер-пупер крутой. Работает он установкой обработчика сигнала SIGPROF, который приходит от таймера.

Суть вопроса:

Прочитал где-то в интернете, что если в процессе много нитей, и какой-то сигнал (не SIGKILL) разблогирован в каждом из них, то ОС передает его одному (произвольному) треду. Мне же надо при получении сигнала от таймера остановить каждый тред и покопаться в его контексте. Как это сделать?

Мои идеи (если вы знаете наверняка, как ответить на мой вопрос, то лучше и не читать):

У меня на уме только один вариант, в котором сигнал будет получать главный тред, потом он каким-то образом приостановит остальные и соберет с них инфу. Как остановить несколько тредов сразу в один момент?

Может годится такой вариант: главный тред получает SIGPROF (в остальных тредах он заблокирован). Обработчик из главного треда посылает каждому созданному треду (их можно хранить в списке) с помощью pthread_kill SIGUSR1, в этом треде он ловится и производятся необходимые действия.

                              /->[Thread 1] --> Handler
                             /
              ------------  / SIGUSR1
 SIGPROF     /            \/
----------->/ Main thread  \
            \              /
             \            /\
              ------------  \SIGUSR1
                             \
                              \->[Thread 2] -> Handler

Дискач. Позову спеца mashina

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

http://stackoverflow.com/questions/12952262/signal-handler-function-in-multit...

Вот там есть такой ответ:

Signal handlers are per-process state - that is, all the threads in a process share the same set of installed signal handler functions.

Signal masks are per-thread state. Signals can be blocked or unblocked on a per-thread basis.

Signals can be process- or thread-directed. If a signal is process-directed, then an arbitrary thread which does not have the signal blocked is chosen to handle it.

A simple way to handle signals in a multi-threaded application is to create one thread as a dedicated signal-handling thread. All signals of interest are blocked in every thread; no signal handlers are established; and the signal-handling thread calls sigwaitinfo() in a loop, acting on the signals as they're received.

then an arbitrary thread which does not have the signal blocked is chosen to handle it.

Тогда как получается, что все треды по твоей ссылке получили ~1000 сигналов? В чём магия? Как я понимаю, в лучшем случае должно быть ~1000/4 сигналов на тред, а в худшем 1000 сигналов на один тред и 0 на другие

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

Похоже ты прав, заменил SIGPROF на SIGTERM и стал killall'ить. В итоге сигналы получал только 1 тред

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

В чём магия?

Да какая разница. Работает - и хорошо. Да, это скорее всего особенность SIGPROF

Вот как у него получились такие ровные значения? я попробовал пример (только изменил ф-цию idle_time), разброс процентов в 10

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

я попробовал пример (только изменил ф-цию idle_time), разброс процентов в 10

Аналогично.

niemand ()

tailgunner, AptGet

Вот ещё проблема - мне из обработчика нужно записать измерения в специальную структуру. Так как в многонитевых процессах из обработчиков сигналов нельзя изменять shared объекты кроме volatile sig_atomic_t, структура планируется своя на каждый процесс. Но как получить к ней доступ из обработчика. Тот же pthread_getspecific можно считать в том же линуксе async-signal-safe?

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

Я бы из обработчика писал нужные данные в файловый дескриптор, это безопасно. А уже в другой нити/процессе менял что там требуется поменять с синхронизацией, как положено.

Тот же pthread_getspecific можно считать в том же линуксе async-signal-safe?

Не знаю насчет линукса, в позиксе ни одна pthread_ функция не безопасна, если я правильно помню.

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

Не знаю насчет линукса, в позиксе ни одна pthread_ функция не безопасна, если я правильно помню.

Точняк, но походу она работает

http://pastebin.com/xe4T6zui

Можешь попробовать запустить у себя. Тот чувак по первой ссылке в треде запускал у себя pthread_self и вроде тоже ничего так

niemand ()

У меня на уме только один вариант, в котором сигнал будет получать главный тред, потом он каким-то образом приостановит остальные и соберет с них инфу. Как остановить несколько тредов сразу в один момент?

POSIX, AFAIK, так и рекомендует делать — ловить сигналы в одном, выделенном для этого потоке (главном, например). А потом обрабатывать их соответствующим образом.

Ну и SIGSTOP/SIGCONT.

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

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

структура планируется своя на каждый процесс

На процесс или нить?

tailgunner ★★★★★ ()
Ответ на: комментарий от niemand
$ ./thread2 
Signals caught after 4x10 seconds by thread 0: 905 
Signals caught after 4x10 seconds by thread 1: 4 
Signals caught after 4x10 seconds by thread 2: 917 
Signals caught after 4x10 seconds by thread 3: 880 

На линуксе работает, в смысле запускается, но нужно проверять, правильно ли оно считает.

$ ./thread2 
Signals caught after 4x10 seconds by thread 0: 50 
Signals caught after 4x10 seconds by thread 1: 0 
Signals caught after 4x10 seconds by thread 2: 0 
Signals caught after 4x10 seconds by thread 3: 0 

На макоси явно сломано.

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

Вон в sbcl вообще в sigprof-handler мьютекс держится, такие дела

Я могу представить как сделать чтобы оно работало, но проблема UB в том что полезавтра Дреппер чуть подправит магнитное поле glibc и код сломается, а Дреппер даже версию библиотеки не поднимет. И формально будет прав, как и в случае с memcpy.

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

На процесс или нить?

На нить, да.

Насколько я понимаю, тебе нужно просто записать небольшую порцию данных в общую память?

Угу

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

Молодец этот ваш Дреппер, чо. Пусть быдлокодеры соснут

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

тебе нужно просто записать небольшую порцию данных в общую память?

Угу

Тогда тебе нужна атомарная операция «увеличить счетчик на N и вернуть предыдущее значение». Если не заморачиваться увеличением объема общей памяти на ходу, должно хватить.

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

Signals caught after 4x10 seconds by thread 1: 4

На бзде вообще всё ровно. Можно будет приводить это как аргумент в пользу бзди в срачах против ляликсоидов ;)

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