Диспозиция такая: есть два потока, один рисует данные opengl'ем, второй в фоне грузит куски данных. Реализована, соответственно, очередь запросов, защищённая мутексом:
// Главный поток
{
while (1) {
pthread_mutex_lock(mutex);
...
отрисовка_данных(dataset);
...
queue.push_back(request);
...
pthread_mutex_unlock(mutex); /* 1 */
}
}
// Рабочий поток:
{
pthread_mutex_lock(mutex);
while (!die_flag) {
while (queue.empty())
pthread_cond_wait(condvar, mutex);
request = queue.pop_front();
pthread_mutex_unlock(mutex);
data = долгая_обработка_куска_данных(request);
pthread_mutex_lock(mutex);
dataset.push_back(data);
}
pthread_mutex_unlock(mutex);
}
Идея, думаю, понятна - долгая операция происходит в потоке никому не мешая, мутекс захватывается вторым потоком только чтобы вытащить запрос из очереди либо добавить кусок данных в общий датасет (тут задержек быть не может, везде списки), соответственно главный поток прерывается не дольше чем на время операции со списком.
На деле же происходит следующая неприятая вещь: первый поток после рендеринга и добавления нескольких запросов в очередь вызывает pthread_mutex_unlock (/* 1 */) и не возвращается из неё 0.1 секунды, за которые второй поток и ухитряется обработать аж десяток кусков данных, соответственно, отображение в главном потоке заметно лагает. Насколько я понимаю, получается так потому что у первого потока, успевшего за время рендеринга пожрать циклов CPU, понижается приоритет, а т.к. второй поток это время спал, он вытесняет первый пока не догонит его по использованию CPU. Вставка sched_yield во второй поток помогает, но сейчас используется два потока, и лаги, хоть и менее заметны, всё ещё присутствуют. Как я понимаю, несколько рабочих потоков будут просто переключаются друг на друга, но не на главный.
Собственно вопрос: как избавиться от лагов? Я так понимаю, приоритеты потокам выставлять не очень хорошо потому что условиях нехватки CPU (т.е. 1 ядро занятое на 100%) поток с меньшим приоритетом будет голодать, а значит данные грузиться не будут. В идеале нужно чтобы главный поток не вытеснялся более чем на 0.01 сек, но при этом чтобы CPU с другими потоками получал поровну.