我有两个线程,一个在紧密循环中工作,另一个偶尔需要与第一个执行同步:
// thread 1
while(1)
{
lock(work);
// perform work
unlock(work);
}
// thread 2
while(1)
{
// unrelated work that takes a while
lock(work);
// synchronizing step
unlock(work);
}
我的意图是,通过获取锁,线程2可以有效地暂停线程1并执行必要的同步。线程1还可以提供暂停,解锁,如果线程2没有等待锁定,则重新锁定并返回工作。
我遇到的问题是互斥是不公平的,所以线程1快速重新锁定互斥锁并使线程2变得饥饿。我试图使用pthread_yield
,到目前为止似乎运行正常但是我不确定它是否适用于所有系统/核心数量。有没有办法保证线程1总能屈服于线程2,即使在多核系统上也是如此?
处理此同步过程的最有效方法是什么?
答案 0 :(得分:6)
您可以在pthreads互斥锁之上构建一个FIFO“票证锁”,沿着以下几行:
#include <pthread.h>
typedef struct ticket_lock {
pthread_cond_t cond;
pthread_mutex_t mutex;
unsigned long queue_head, queue_tail;
} ticket_lock_t;
#define TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }
void ticket_lock(ticket_lock_t *ticket)
{
unsigned long queue_me;
pthread_mutex_lock(&ticket->mutex);
queue_me = ticket->queue_tail++;
while (queue_me != ticket->queue_head)
{
pthread_cond_wait(&ticket->cond, &ticket->mutex);
}
pthread_mutex_unlock(&ticket->mutex);
}
void ticket_unlock(ticket_lock_t *ticket)
{
pthread_mutex_lock(&ticket->mutex);
ticket->queue_head++;
pthread_cond_broadcast(&ticket->cond);
pthread_mutex_unlock(&ticket->mutex);
}
在这种方案下,当线程在受到故障保护的关键部分内时,不会保留低级pthreads互斥锁,允许其他线程加入队列。
答案 1 :(得分:5)
在您的情况下,最好使用condition variable在需要唤醒并执行所有必需操作时通知第二个线程。
答案 2 :(得分:2)
pthread
在其API中提供了线程优先级的概念。当两个线程通过互斥锁竞争时,调度策略确定哪个线程将获得它。函数pthread_attr_setschedpolicy
允许您设置,pthread_attr_getschedpolicy
允许检索信息。
现在是坏消息:
SCHED_FIFO
,SCHED_RR
,SCHED_OTHER
和SCHED_SPORADIC
),但是in this question,只回答here Linux上支持1}} 如果我是你,我会试一试,但不要期望太多。 SCHED_OTHER
对我来说似乎更有希望。更多信息{{3}}。
答案 3 :(得分:0)
上面的门锁似乎是最好的。但是,为了确保你的pthread_yield正常工作,你可以让bool等待,由thread2设置和重置。只要设置了bool等待,thread1就会产生。
答案 4 :(得分:0)
这是一个简单的解决方案,适用于您的情况(两个线程)。如果您正在使用std::mutex
,则此类是替代品。将你的互斥锁更改为这种类型,并保证如果一个线程持有锁而另一个线程正在等待它,一旦第一个线程解锁,第二个线程将在第一个线程再次锁定它之前获取锁。
如果两个以上的线程碰巧同时使用互斥锁,它仍然会起作用,但不保证公平性。
如果您使用普通pthread_mutex_t
,则可以根据此示例轻松更改锁定代码(解锁保持不变)。
#include <mutex>
// Behaves the same as std::mutex but guarantees fairness as long as
// up to two threads are using (holding/waiting on) it.
// When one thread unlocks the mutex while another is waiting on it,
// the other is guaranteed to run before the first thread can lock it again.
class FairDualMutex : public std::mutex {
public:
void lock() {
_fairness_mutex.lock();
std::mutex::lock();
_fairness_mutex.unlock();
}
private:
std::mutex _fairness_mutex;
};