Я хотел бы иметь возможность принудительно переключать контекст из одного потока в другой.Поэтому я реализовал следующую процедуру блокировки:
#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 потоками, пытающимися получить и снять блокировку через случайные интервалы, каждыйвремя от времени acqu () возвращает EPROTO
, указывая, что кто-то вызвал pthread_cond_signal
без предварительной установки lock_taken = FALSE
.
Почему это так?Кажется, что процессор иногда не видит новое значение lock_taken
, поэтому я уже сделал переменные изменчивыми.Но это все еще происходит ...