假设以下代码正在被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平台的解决scheme,并且应该使用pthreads。 我并不在乎任何其他平台。
另外请注意,我并不是真的想把这3个线程作为实时的,我希望他们展示他们的违规行为(调度和优先级),除了在上面提到的一小段代码中,我希望他们总是优先获取锁。
我已经阅读了一些关于Linux调度策略和调度优先级的手册页,但不能真正做出:(
这会工作吗? 你能帮我完成上述任务所需的确切的pthread API吗?
关心lali
据我所知,唯一可以确保这一点的方法就是编写一个自己喜欢的锁。
您将需要条件变量,并计数等待低/高优先级线程的数量。
就您所需要的概念和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()
。
设计很简单。 在关键部分mutex ->cs_mutex
中保持高优先级的线程,低优先级的线程被保存在条件变量中。 条件变量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);
(前两次有错误,请跳到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
编辑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
要用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
是一个优先级队列的基本形式。
原生的方法是为你的互斥量(使用pthread_mutex_attr)启用优先级继承,并使用pthread的线程优先级来执行你所需要的。 它只需要很少的几行代码,而且你没有重新发明轮子。 好的一面,它也可以与RT或FIFO调度程序,而你的自制软件版本不会。
然后,只要优先级较高的线程等待一个优先级较低的线程获得的互斥锁,内核就会“提升”低优先级的线程,从而可以调度高优先级的线程,从而给它一个时间片释放锁。 一旦锁定被释放,高优先级的线程被安排。 这是在内核中完成的最低延迟。