I would like to be able wait/post more than one resource at a time. Is there a built-in c structure and interface that allows for this?
Currently I am using semaphore.h
however this interface has the limitation that it can only request a single resource at a time.
I could do something like this:
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
But this would be time consuming if resources
is large and I would also need to add another lock before this so that I am guaranteed that the requester has priority over other threads that may be requesting resources.
It would end up looking something like this:
sem_wait(my_lock);
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
sem_post(my_lock);
not to mention extra error checks that would need to happen.
What I would like to be able to do is something like this:
sem_wait(my_lock, resources);
This would simply wait until all resources are available and then return after decrementing the semaphore by the requested number of resources. I feel like I've seen something like this a while back but can't seem to figure it out.
You are presently using POSIX semaphores. They do not directly afford the possibility of atomically changing the semaphore value by more than one, except when creating a new semaphore.
System V semaphores (semget
/ semctl
/ semop
) are generally considered inferior, but they do have some features that the POSIX flavor lacks, and this is one of them. Specifically, you can use semop()
to atomically deduct any positive number from the semaphore's value, blocking until this can be done without reducing the value below zero.
But System V IPC is enough of a pain overall that I'd suggest instead setting up a shared variable representing the number of resources presently available, and using a mutex + condition variable instead of a semaphore. That would look something like this:
unsigned resources_available = ALL_RESOURCES;
pthread_mutex_t resource_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t resource_cv = PTHREAD_COND_INITIALIZER;
// ...
int acquire_resources(unsigned resources_wanted) {
int result;
// ...
result = pthread_mutex_lock(resource_mutex);
// handle errors ...
while (resources_available < resources_wanted) {
result = pthread_cond_wait(resource_cv, resource_mutex);
// handle errors ...
}
resources_available -= resources_wanted;
result = pthread_mutex_unlock(resource_mutex);
// ...
}
int release_resources(unsigned resources_released) {
int result;
// ...
result = pthread_mutex_lock(resource_mutex);
// handle errors ...
resources_available += resources_released;
result = pthread_cond_broadcast(resource_cv);
// handle errors ...
result = pthread_mutex_unlock(resource_mutex);
// ...
}