如何允许某些线程优先锁定互斥锁使用PTHREADS

假设以下代码由10个线程执行。
pthread_mutex_lock(&lock)
Some trivial code
pthread_mutex_unlock(&lock)
为了解释的目的,我们可以说线程是T1,T2,T3 ...... T10。 我的要求是只要T1或T2或T3(即T1,T2或T3中的任何一个)等待获取锁定,其他线程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吗? 问候 拉利     
已邀请:
据我所知,唯一可以真正保证这一点的方法就是写一个像你自己一样的锁。但是@ xryl669的答案建议使用线程优先级和优先级继承当然值得考虑,如果它适用于您的用例。 要自己实现它,您将需要条件变量和等待低/高优先级线程数的计数。 就你需要的概念和API而言,它与实现读/写锁相当类似(但是你需要的语义完全不同,显然 - 但如果你理解了r / w锁是如何工作的,那么你'我将了解如何实现你想要的东西)。 您可以在此处看到读写锁的实现: http://ptgmedia.pearsoncmg.com/images/0201633922/sourcecode/rwlock.c 在优先级较低的线程中,您需要等待高优先级线程完成,就像读者等待编写器完成一样。 (上面的代码是从它上面得到的一本很棒的posix线程书btw,http://www.informit.com/store/product.aspx?isbn = 0201633922)     
这是我的实施。低优先级线程使用
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);
}
    
或者,您可以为更高优先级的线程引入另一个锁。考虑以下伪代码(我不熟悉pthread语义,但我相信这并不难将代码映射到所需的调用) 编辑(thanx JosephH) 将exec信号量设置为3(高prio线程数) 请注意,
pend(exec,3);
表示此挂起将一直睡眠,直到所有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);
    
本机方法是为您的互斥锁启用优先级继承(使用pthread_mutex_attr),并使用pthread的线程优先级来执行您需要的操作。 它只需要很少的代码行,而你并没有重新发明轮子。 好的方面,它也适用于RT或FIFO调度程序,而您的自制程序版本则不行。 然后,只要具有高优先级的线程等待由较低优先级的线程获取的互斥锁,内核就“提升”低优先级线程,以便可以调度它来代替高优先级线程,从而给它一个时间片。释放锁。一旦释放锁定,就会安排高优先级线程。这是你在内核中完成的最低延迟。     
(前两次尝试有错误,请跳转到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
推理: 一些线程将竞争两个锁,因此将具有较低的优先级,并且一些线程将仅竞争一个锁,因此将具有更高的优先级。 差异可能是微不足道的,然后解决方案是在获得第一次锁定和为较高优先级线程尝试第二次锁定之间引入一些延迟,在这种情况下,较高优先级的线程将有机会获得lock2。 (免责声明:谈到这个时我是新手) 编辑: 另一种尝试/方法
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
EDIT2:另一种尝试(试图在这里学习一些东西)
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
    
要使用pthread实现它,您需要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 );
}
该代码还处理来自ѭ14的虚假唤醒,但坦率地说,我从未见过这种情况。 EDIT1。注意,上面的
prio_lists
是优先级队列的原始形式。     

要回复问题请先登录注册