Я испытываю странное поведение в программном обеспечении, над которым я работаю. Это контроллер в режиме реального времени, написанный на С++, работающий на Linux, и он широко использует многопоточность.
Когда я запускаю программу, не спрашивая ее в реальном времени, все работает так, как я ожидаю. Но когда я прошу переключиться в режим реального времени, есть отчетливо воспроизводимая ошибка, которая позволяет сбой приложения. Я думаю, это должно быть какая-то тупиковая вещь, потому что это мьютекс, который набирает тайм-аут и в конечном итоге вызывает утверждение.
Мой вопрос: как его отыскать. Глядя на обратную линию от произведенного ядра, не очень полезно, поскольку причина проблемы лежит где-то в прошлом.
В следующем коде происходит переключение между режимами "normal" и "realtime":
В main.cpp(упрощенный код возврата проверяется через утверждения):
if(startAsRealtime){
struct sched_param sp;
memset(&sp, 0, sizeof(sched_param));
sp.sched_priority = 99;
sched_setscheduler(getpid(), SCHED_RR, &sp);}
В каждом потоке (упрощенный код возврата проверяется посредством утверждений):
if(startAsRealtime){
sched_param param;
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_getschedparam(&attr, ¶m);
param.sched_priority = priority;
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, ¶m);}
Заранее спасибо
Если вы используете glibc
как свою библиотеку C, вы можете использовать ответ на вопрос Возможно ли перечислить мьютексы, которые содержат нить, чтобы найти из потока, который удерживает мьютекс, который отключается. Это должно начать сужать вещи - вы можете проверить этот поток и выяснить, почему он не отказывается от мьютекса.
Один из ваших потоков в реальном времени может вращаться в цикле (не уступая), таким образом, голодающие другие потоки и приводящие к таймауту мьютекса.
Также может быть состояние гонки, которое проявляется только при переключении в режим реального времени. Время событий в режиме реального времени вызывает тупик.
Если у вас есть места, где вы приобретаете несколько уровней блокировок или блокируете рекурсивно, это должны быть первые места, которые вы подозреваете.
Если вы действительно не знаете, где проблема, попробуйте использовать метод двоичного поиска для брекетинга проблемы. Рекурсивно вырезать половину функциональности, пока вы не уменьшите ее до фактической проблемы. Возможно, вам придется издеваться над некоторыми подсистемами, которые временно вырезаны.
Вы можете применить эту технику двоичного поиска к вашим тайм-аутам получения мьютекса, чтобы найти, кто из них виновен.