强制线程上下文切换

时间:2011-12-04 21:39:32

标签: c pthreads

我希望能够强制从一个线程切换到另一个线程。因此,我实现了以下锁定过程:

#define TRUE  (1==1)
#define FALSE (0==1)

#include <pthread.h>

int acquire(void);
int release(void);
int c_yield(int count);

// Who was the last to acquire the lock
static volatile pthread_t lock_owner;

// Is the lock currently taken
static volatile int lock_taken = FALSE;

/* This variable indicates how many threads are currently waiting for
 * the lock. */
static volatile int lock_wanted = 0;

/* Mutex for protecting access to lock_wanted, lock_owner and
 * lock_taken */
static pthread_mutex_t mutex;

/* Condition even to notify when the lock becomes available */
static pthread_cond_t cond;

void init_lock(void) {
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
}

int acquire(void) {
    pthread_mutex_lock(&mutex);
    if(lock_taken) {
        lock_wanted++;
        pthread_cond_wait(&cond, &mutex);
        lock_wanted--;
    } 
    if(lock_taken) {
        pthread_mutex_unlock(&mutex);
        return EPROTO;
    } 
    lock_taken = TRUE;
    lock_owner = pthread_self();
    return pthread_mutex_unlock(&mutex);
}

int release(void) {
    pthread_mutex_lock(&mutex);
    lock_taken = FALSE;
    if(lock_wanted > 0) {
        pthread_cond_signal(&cond);
    }
    return pthread_mutex_unlock(&mutex);
}

使用另一个方法(未显示),然后我可以实现yield(),只有在没有线程等待锁定时,或者在至少一个其他线程有机会运行之后才会返回。

这个实现大部分时间都可以正常工作,但是如果我用~50个线程对它进行压力测试,试图以随机的间隔获取和释放锁,每隔一段时间,acquire()就会返回EPROTO,表示有人在没有先设置pthread_cond_signal的情况下调用了lock_taken = FALSE

为什么?似乎CPU有时看不到lock_taken的新值,这就是我已经使变量变为volatile的原因。但它仍在发生......

1 个答案:

答案 0 :(得分:7)

if(lock_taken) {
    lock_wanted++;
    pthread_cond_wait(&cond, &mutex);
    lock_wanted--;
} 

这应该是while(lock_taken),而不是if。有几个原因你可能会从pthread_cond_wait中醒来,但是在你安排的时候找到另一个线程所采取的锁定。一个是如果有一个虚假的唤醒。另一个是在我们阻塞之后另一个线程进入acquire,找不到锁定,并在此线程再次获取互斥锁之前自行获取。

规范的方式是:

lock_wanted++;
while(lock_taken) pthread_cond_wait(&cond, &mutex);
lock_wanted--;

摆脱所有volatile,它们会损害性能并且不需要。因为互斥量足够同步,所以不需要其他任何东西。 (并且,对于任何查看您的代码的人来说,他们都表示您不理解线程同步,并试图将它们“洒入”,直到它恰好正常工作。)