pthread implementation of a ticket lock
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef UC_TICKET_LOCK_H_
|
||||||
|
#define UC_TICKET_LOCK_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/** An fair alternative to a bare pthread_mutex_t to prevent starvation*/
|
||||||
|
struct UCTicketLock {
|
||||||
|
pthread_cond_t cond;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
unsigned long queue_head, queue_tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Static initializer for an UCTicketLock. Use as e.g
|
||||||
|
*
|
||||||
|
* struct UCTicketLock my_lock = UC_TICKET_LOCK_INITIALIZER;
|
||||||
|
*/
|
||||||
|
#define UC_TICKET_LOCK_INITIALIZER { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,0, 0}
|
||||||
|
|
||||||
|
/** Initialize a UCTicketLock.
|
||||||
|
* The default attributes for the pthread mutex and condition variable is used.
|
||||||
|
*
|
||||||
|
* @return 0 on success, errno value on failure
|
||||||
|
*/
|
||||||
|
int uc_ticket_lock_init(struct UCTicketLock *lock);
|
||||||
|
|
||||||
|
/** Initialize a UCTicketLock with attributes
|
||||||
|
*
|
||||||
|
* @param mattr attribute used for the mutex, or NULL
|
||||||
|
* @param cattr attribute used for the condition variable, or NULL
|
||||||
|
*
|
||||||
|
* @return 0 on success, errno value on failure
|
||||||
|
*/
|
||||||
|
int uc_ticket_lock_init_ex(struct UCTicketLock *lock, pthread_mutexattr_t *mattr, pthread_condattr_t *cattr);
|
||||||
|
|
||||||
|
/** Acquire the lock
|
||||||
|
*/
|
||||||
|
void uc_ticket_lock(struct UCTicketLock *lock);
|
||||||
|
|
||||||
|
/** Release the lock
|
||||||
|
*/
|
||||||
|
void uc_ticket_unlock(struct UCTicketLock *lock);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "ucore/ticket_lock.h"
|
||||||
|
|
||||||
|
int uc_ticket_lock_init(struct UCTicketLock *lock)
|
||||||
|
{
|
||||||
|
return uc_ticket_lock_init_ex(lock, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int uc_ticket_lock_init_ex(struct UCTicketLock *lock, pthread_mutexattr_t *mattr, pthread_condattr_t *cattr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
lock->queue_head = 0;
|
||||||
|
lock->queue_tail = 0;
|
||||||
|
|
||||||
|
rc = pthread_mutex_init(&lock->mutex, mattr);
|
||||||
|
assert(rc == 0);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = pthread_cond_init(&lock->cond, cattr);
|
||||||
|
if (rc != 0) {
|
||||||
|
pthread_mutex_destroy(&lock->mutex);
|
||||||
|
}
|
||||||
|
assert(rc == 0);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_ticket_lock(struct UCTicketLock *lock)
|
||||||
|
{
|
||||||
|
unsigned long queue_me;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lock->mutex);
|
||||||
|
queue_me = lock->queue_tail++;
|
||||||
|
while (queue_me != lock->queue_head)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&lock->cond, &lock->mutex);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&lock->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_ticket_unlock(struct UCTicketLock *lock)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&lock->mutex);
|
||||||
|
lock->queue_head++;
|
||||||
|
pthread_cond_broadcast(&lock->cond);
|
||||||
|
pthread_mutex_unlock(&lock->mutex);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user