简体   繁体   English

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

[英]How to allow certain threads to have priority in locking a mutex use PTHREADS

Assume that the following code is being executed by 10 threads. 假设以下代码由10个线程执行。

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

For purpose of explanations lets say the threads are T1, T2, T3.....T10. 为了解释的目的,我们可以说线程是T1,T2,T3 ...... T10。 My requirement is that as long as T1 or T2 or T3( ie any of T1, T2 or T3) is waiting for acquiring a lock, the other threads it T4, T5, T6.....T10 should not be able to acquire the lock ie T1, T2 and T3 should have precedence in acquiring the lock with respect to other threads. 我的要求是只要T1或T2或T3(即T1,T2或T3中的任何一个)等待获取锁定,其他线程T4,T5,T6 ...... T10应该无法获取锁定即T1,T2和T3应优先获取相对于其他线程的锁定。

I guess it could be done by increasing the priority of threads T1, T2 and T3 我想这可以通过增加线程T1,T2和T3的优先级来完成

ie here is the pseudo code 即这是伪代码

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

Please note that I want a solution that is works for Linux platform and should use pthreads. 请注意,我想要一个适用于Linux平台的解决方案,并且应该使用pthreads。 I don't really care about any other platform. 我真的不关心任何其他平台。

Also note that I don't really want to make these 3 threads as realtime, I want them to exhibit their defualt behaviour(scheduling and priority) except that in the above mentioned small piece of code I want them to always have precedence in acquiring lock. 还要注意我真的不想让这3个线程成为实时,我希望它们展示它们的defualt行为(调度和优先级),除了在上面提到的一小段代码中我希望它们始终具有获取锁定的优先权。

I have read some man pages about scheduling policies and scheduling priorities in Linux but can't really make out :( 我已经阅读了一些关于在Linux中调度策略和调度优先级的手册,但实际上并不能解决:(

Will this work? 这会有用吗? Can you help me with the exact pthread API required to accomplish the above task? 你能帮助我完成上述任务所需的确切pthread API吗?

Regards lali 关心lali

Here's my implementation. 这是我的实施。 Low priority threads use prio_lock_low() and prio_unlock_low() to lock and unlock, high priority threads use prio_lock_high() and prio_unlock_high() . 低优先级线程使用prio_lock_low()prio_unlock_low()来锁定和解锁,高优先级线程使用prio_lock_high()prio_unlock_high()

The design is quite simple. 设计非常简单。 High priority threads are held at the critical section mutex ->cs_mutex , low priority threads are held at the condition variable. 高优先级线程保存在临界区mutex ->cs_mutex ,低优先级线程保持在条件变量。 The condition variable mutex is only held around updates to the shared variable and signalling of the condition variable. 条件变量互斥锁仅保留在共享变量的更新和条件变量的信令周围。

#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);
}

As I understand it, the only way you can truly guarantee this would be to write a lock that works like that yourself. 据我所知,唯一可以真正保证这一点的方法就是写一个像你自己一样的锁。 However @xryl669's answer that suggests using thread priority and priority inheritance is certainly worthy of consideration if it works for your use case. 但是@ xryl669的答案建议使用线程优先级和优先级继承当然值得考虑,如果它适用于您的用例。

To implement it yourself, you will need condition variables and counts of the number of waiting low / high priority threads. 要自己实现它,您将需要条件变量和等待低/高优先级线程数的计数。

In terms of the concepts and APIs you'll need, it is relatively similar to implementing a read/write lock (but the semantics you need are completely different, obviously - but if you understood how the r/w lock is working, you'll understand how to implement what you want). 就你需要的概念和API而言,它与实现读/写锁相当类似(但是你需要的语义完全不同,显然 - 但如果你理解了r / w锁是如何工作的,那么你'我将了解如何实现你想要的东西)。

You can see an implementation of a read write lock here: 您可以在此处看到读写锁的实现:

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

In the lower priority threads, you'd need to wait for high priority threads to finish, in the same way readers wait for writers to finish. 在优先级较低的线程中,您需要等待高优先级线程完成,就像读者等待编写器完成一样。

(The book the above code is taken from it also a great posix threads book btw, http://www.informit.com/store/product.aspx?isbn=0201633922 ) (上面的代码是从它上面得到的一本很棒的posix线程书btw, http://www.informit.com/store/product.aspx? isbn = 0201633922)

The native way is to enable priority inheritance for your mutex (with pthread_mutex_attr), and use pthread's thread priority to perform what you need. 本机方法是为您的互斥锁启用优先级继承(使用pthread_mutex_attr),并使用pthread的线程优先级来执行您需要的操作。 It only requires very few lines of code, and you are not re-inventing the wheel. 它只需要很少的代码行,而你并没有重新发明轮子。 On the good side, it'll also work with RT or FIFO scheduler while your homebrew version will not. 好的方面,它也适用于RT或FIFO调度程序,而您的自制程序版本则不行。

Then, whenever a thread with a high priority waits on a mutex that's acquired by a thread on lower priority, the kernel "boost" the low priority thread so it can be scheduled in place of the high priority thread, thus giving it a timeslice to release the lock. 然后,只要具有高优先级的线程等待由较低优先级的线程获取的互斥锁,内核就“提升”低优先级线程,以便可以调度它来代替高优先级线程,从而给它一个时间片。释放锁。 As soon as the lock is released, the high priority thread is scheduled. 一旦释放锁定,就会安排高优先级线程。 That's the lowest delay you could get since it's done in the kernel. 这是你在内核中完成的最低延迟。

Alternatively you may just introduce another lock for higher priority threads. 或者,您可以为更高优先级的线程引入另一个锁。 consider the following pseudo-code (i am not familiar with the pthread semantics, but i believe this is not hard to map the code to the needed calls) 考虑以下伪代码(我不熟悉pthread语义,但我相信这并不难将代码映射到所需的调用)

EDIT (thanx JosephH) 编辑(thanx JosephH)

introducing the exec semaphore set to 3 (number of high-prio threads) note that pend(exec,3); 引入exec信号量设置为3(高prio线程数)注意pend(exec,3); means that this pend will sleep until all 3 slots are available and will consume them all 意味着这个挂起将睡眠,直到所有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);

(The first two attempts had bugs, pls jump to EDIT2) (前两次尝试有错误,请跳转到EDIT2)

Maybe this would work? 也许这会起作用?

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

Reasoning: Some threads will compete for two locks and therefore will have lower priority and some threads will compete for only one lock and therefore will have higher priority. 推理:有些线程会竞争两个锁,因此优先级较低,一些线程只竞争一个锁,因此优先级更高。 Still the difference might be marginal and then the resolution would be to introduce some lag between acquiring first lock and attempting the second lock for the higher priority threads in which time the higher priority threads will be given a chance to get the lock2. 差异可能是微不足道的,然后解决方案是在获得第一次锁定和为较高优先级线程尝试第二次锁定之间引入一些延迟,在这种情况下,较高优先级的线程将有机会获得lock2。
(disclaimer: I am a newbie when it comes to this) (免责声明:谈到这个时我是新手)

EDIT: Another attempt/approach 编辑:另一种尝试/方法

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: Another attempt (trying to learn something here) 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

To implement that with pthreads you would need N lists, one per thread priority. 要使用pthread实现它,您需要N个列表,每个线程优先级一个。 The lists would contain pointers to the thread's pthread_cond_t variables. 列表将包含指向线程的pthread_cond_t变量的指针。

Schematic untested meta-code: 原型未经测试的元代码:

/* 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 );
}

The code also handles spurious wake-ups from pthread_cond_wait() , but frankly I have never seen that happening. 该代码还处理来自pthread_cond_wait()虚假唤醒,但坦率地说,我从未见过这种情况。

Edit1. EDIT1。 Note that prio_lists above is a primitive form of a priority queue . 请注意,上面的prio_lists优先级队列的原始形式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM