Как позволить определенным потокам иметь приоритет в блокировке взаимоисключающего PTHREADS использования

Предположите, что следующий код выполняется 10 потоками.

pthread_mutex_lock(&lock)
Some trivial code
pthread_mutex_unlock(&lock)

Ради объяснений позволяет, говорят, что потоки являются T1, T2, T3..... T10. Мое требование - то, что, пока T1 или T2 или T3 (т.е. любой из T1, T2 или T3) ожидают получения блокировки, другого i.t T4 потоков, T5, T6..... T10 не должен мочь получить блокировку т.е. T1, T2 и T3 должны иметь приоритет в получении блокировки относительно других потоков.

Я предполагаю, что это могло быть сделано путем увеличения приоритета потоков T1, T2 и T3

т.е. вот псевдо код

if this thread is T1 or T2 or T3
increase its priority 
pthread_mutex_lock(&lock)
Some trivial code
pthread_mutex_unlock(&lock)
if this thread is T1 or T2 or T3 decrease it priority to normal

Обратите внимание на то, что я хочу решение, которое является работами для платформы Linux и должно использовать pthreads. Я действительно не забочусь ни о какой другой платформе.

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

Я прочитал некоторые страницы справочника о планировании политик и планировании приоритетов в Linux, но не могу действительно разобрать :(

Это будет работать? Можно ли помочь мне с точным pthread API, требуемым выполнить вышеупомянутую задачу?

Отношения lali

14
задан bstpierre 20 July 2010 в 03:33
поделиться

5 ответов

Насколько я понимаю, единственный способ действительно гарантировать это - это написать блокировку, которая работает так же самостоятельно. Однако ответ @ xryl669 , в котором предлагается использовать приоритет потока и наследование приоритетов, безусловно, заслуживает рассмотрения, если он работает для вашего варианта использования.

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

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

Вы можете увидеть реализацию блокировки чтения и записи здесь:

http://ptgmedia.pearsoncmg.com/images/0201633922/sourcecode/rwlock.c

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

(Книга с указанным выше кодом взята из нее, кстати, http://www.informit.com/store/product.aspx?isbn=0201633922 )

6
ответ дан 1 December 2019 в 12:51
поделиться

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

EDIT (thanx JosephH)

, вводя семафор exec, установленный на 3 (количество потоков с высокой приоритетностью) обратите внимание, что pend (exec, 3); означает, что этот pend будет бездействовать до тех пор, пока все 3 слота не станут доступны, и поглотит их все



//init
exec = semaphore(3,3);

//========================

if this is NOT thread (t1,t2,t3)
    lock(low_prio);
    sem_pend(exec,3);
else
    sem_pend(exec,1);
lock(high_prio);
//...
unlock(high_prio);
if this is NOT thread (t1,t2,t3)
    sem_release(exec,3);
    sleep(0); //yield();  //ensures that sem_pend(exec,1) is executed
    unlock(low_prio);
else
    sem_release(exec,1);
2
ответ дан 1 December 2019 в 12:51
поделиться

(Первые две попытки имели ошибки, пожалуйста, перейдите к EDIT2)

Может, это сработает?

if NOT this thread is T1 or T2 or T3
    pthread_mutex_lock(&lock1) // see note below
    pthread_mutex_lock(&lock2)
    Some trivial code
    pthread_mutex_unlock(&lock2)
    pthread_mutex_unlock(&lock1)
else
    pthread_mutex_lock(&lock2)
    Some trivial code
    pthread_mutex_unlock(&lock2)        
end if

Обоснование: Некоторые потоки будут конкурировать за две блокировки и, следовательно, будут иметь более низкий приоритет, а некоторые потоки будут конкурировать только за одну блокировку и, следовательно, будут иметь более высокий приоритет. Тем не менее, разница может быть незначительной, и тогда разрешается введение некоторой задержки между получением первой блокировки и попыткой второй блокировки для потоков с более высоким приоритетом, при этом потокам с более высоким приоритетом будет предоставлена ​​возможность получить блокировку2.
(отказ от ответственности: я новичок, когда дело доходит до этого)

РЕДАКТИРОВАТЬ: Другая попытка / подход

if NOT (this thread is T1 or T2 or T3)  
    pthread_mutex_lock(&lock1)
    if pthread_mutex_trylock(&lock2) == 0  // low priority threads will not get queued
        Some trivial code
        pthread_mutex_unlock(&lock2)
    end if
    pthread_mutex_unlock(&lock1)
else 
    if (this thread is T1 or T2 or T3)
        pthread_mutex_lock(&lock2)
        Some trivial code
        pthread_mutex_unlock(&lock2)        
    end if
end if

РЕДАКТИРОВАТЬ2: Еще одна попытка (попытка узнать что-то здесь)

if NOT (this thread is T1 or T2 or T3)  
    pthread_mutex_lock(&lock1)
    while !(pthread_mutex_trylock(&lock2) == 0)
        pthread_yield()
    Some trivial code
    pthread_mutex_unlock(&lock2)
    pthread_mutex_unlock(&lock1)
else 
    if (this thread is T1 or T2 or T3)
        pthread_mutex_lock(&lock2)
        Some trivial code
        pthread_mutex_unlock(&lock2)        
    end if
end if
0
ответ дан 1 December 2019 в 12:51
поделиться

Чтобы реализовать это с помощью pthreads, вам потребуется N списков, по одному на приоритет потока. Списки будут содержать указатели на переменные потока pthread_cond_t.

Схема непроверенного метакода:

/* the main lock */
pthread_mutex_t TheLock = PTHREAD_MUTEX_INITIALIZER;

/* service structures: prio lists and the lock for them */
pthread_mutex_t prio_list_guard = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t *prio_lists[MY_MAX_PRIO][MY_MAX_THREAD]; /* 0 == highest prio */

/* lock */
void
prio_lock(int myprio)
{
    pthread_cond_t x;

    pthread_mutex_lock( &prio_list_guard );

    if (0 == pthread_mutex_trylock( &TheLock )) {
        pthread_mutex_unlock( &prio_list_guard );
        return 0;
    }

    pthread_cond_init( &x, 0 );
    LIST_ADD( prio_lists[myprio], &x )

    while(1)    /* handle spurious wake-ups */
    {
        pthread_cond_wait( &prio_list_guard, &x );
        if (0 == pthread_mutex_trylock( &TheLock )) 
        {
            LIST_REMOVE( prio_lists[myprio], &x );
            pthread_mutex_unlock( &prio_list_guard );
            return 0;
        }
    }
}

/* unlock */
void
prio_unlock()
{
    int i;
    pthread_cond_t *p;

    pthread_mutex_lock( &prio_list_guard );

    for (i=0; i<MY_MAX_PRIO; i++)
    {
        if ((p = LIST_GETFIRST( prio_lists[i] )))
        {
            pthread_cond_signal( p );
            break;
        }
    }

    pthread_mutex_unlock( &TheLock );

    pthread_mutex_unlock( &prio_list_guard );
}

Код также обрабатывает ложные пробуждения от pthread_cond_wait () , но, честно говоря, я никогда не видел, чтобы это происходило.

Edit1. Обратите внимание, что prio_lists выше является примитивной формой очереди приоритетов .

0
ответ дан 1 December 2019 в 12:51
поделиться

Вот моя реализация. Потоки с низким приоритетом используют prio_lock_low () и prio_unlock_low () для блокировки и разблокировки, потоки с высоким приоритетом используют prio_lock_high () и prio_unlock_high () ].

Конструкция довольно проста. Потоки с высоким приоритетом удерживаются в мьютексе критической секции -> cs_mutex , потоки с низким приоритетом удерживаются в переменной условия. Мьютекс условной переменной удерживается только вокруг обновлений общей переменной и сигнализации условной переменной.

#include <pthread.h>

typedef struct prio_lock {
    pthread_cond_t cond;
    pthread_mutex_t cv_mutex; /* Condition variable mutex */
    pthread_mutex_t cs_mutex; /* Critical section mutex */
    unsigned long high_waiters;
} prio_lock_t;

#define PRIO_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }

void prio_lock_low(prio_lock_t *prio_lock)
{
    pthread_mutex_lock(&prio_lock->cv_mutex);
    while (prio_lock->high_waiters || pthread_mutex_trylock(&prio_lock->cs_mutex))
    {
        pthread_cond_wait(&prio_lock->cond, &prio_lock->cv_mutex);
    }
    pthread_mutex_unlock(&prio_lock->cv_mutex);
}

void prio_unlock_low(prio_lock_t *prio_lock)
{
    pthread_mutex_unlock(&prio_lock->cs_mutex);

    pthread_mutex_lock(&prio_lock->cv_mutex);
    if (!prio_lock->high_waiters)
        pthread_cond_signal(&prio_lock->cond);
    pthread_mutex_unlock(&prio_lock->cv_mutex);
}

void prio_lock_high(prio_lock_t *prio_lock)
{
    pthread_mutex_lock(&prio_lock->cv_mutex);
    prio_lock->high_waiters++;
    pthread_mutex_unlock(&prio_lock->cv_mutex);

    pthread_mutex_lock(&prio_lock->cs_mutex);
}

void prio_unlock_high(prio_lock_t *prio_lock)
{
    pthread_mutex_unlock(&prio_lock->cs_mutex);

    pthread_mutex_lock(&prio_lock->cv_mutex);
    prio_lock->high_waiters--;
    if (!prio_lock->high_waiters)
        pthread_cond_signal(&prio_lock->cond);
    pthread_mutex_unlock(&prio_lock->cv_mutex);
}
11
ответ дан 1 December 2019 в 12:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: