是否有允许等待多个资源的内置信号量结构?
Is there a built-in semaphore structure that allows for waiting on more than one resource?
我希望一次能够 wait/post 多个资源。是否有允许这样做的内置 C 结构和接口?
目前我正在使用semaphore.h
但是这个接口有一个限制,它一次只能请求一个资源。
我可以这样做:
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
但如果resources
很大,这会很耗时,我还需要在此之前添加另一个锁,以确保请求者优先于可能正在请求资源的其他线程。
它最终看起来像这样:
sem_wait(my_lock);
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
sem_post(my_lock);
更不用说需要进行的额外错误检查了。
我希望能够做的是这样的事情:
sem_wait(my_lock, resources);
这将简单地等到所有资源都可用,然后 return 在按请求的资源数量递减信号量之后。我觉得我前段时间看到过类似的东西,但似乎无法理解。
您目前正在使用 POSIX 信号量。它们不直接提供以原子方式将信号量值更改超过 1 的可能性,除非创建新的信号量。
System V 信号量 (semget
/ semctl
/ semop
) 通常被认为较差,但它们确实具有 POSIX 风格所缺乏的一些功能,而这是其中之一。具体来说,您可以使用 semop()
来 原子地 从信号量的值中扣除任何正数,阻塞直到可以在不将值减少到零以下的情况下完成。
但 System V IPC 总的来说已经够麻烦了,我建议改为设置一个共享变量来表示当前可用资源的数量,并使用互斥锁 + 条件变量而不是信号量。那看起来像这样:
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);
// ...
}
我希望一次能够 wait/post 多个资源。是否有允许这样做的内置 C 结构和接口?
目前我正在使用semaphore.h
但是这个接口有一个限制,它一次只能请求一个资源。
我可以这样做:
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
但如果resources
很大,这会很耗时,我还需要在此之前添加另一个锁,以确保请求者优先于可能正在请求资源的其他线程。
它最终看起来像这样:
sem_wait(my_lock);
for (int i = 0; i < resources; i++)
sem_wait(my_sem);
sem_post(my_lock);
更不用说需要进行的额外错误检查了。
我希望能够做的是这样的事情:
sem_wait(my_lock, resources);
这将简单地等到所有资源都可用,然后 return 在按请求的资源数量递减信号量之后。我觉得我前段时间看到过类似的东西,但似乎无法理解。
您目前正在使用 POSIX 信号量。它们不直接提供以原子方式将信号量值更改超过 1 的可能性,除非创建新的信号量。
System V 信号量 (semget
/ semctl
/ semop
) 通常被认为较差,但它们确实具有 POSIX 风格所缺乏的一些功能,而这是其中之一。具体来说,您可以使用 semop()
来 原子地 从信号量的值中扣除任何正数,阻塞直到可以在不将值减少到零以下的情况下完成。
但 System V IPC 总的来说已经够麻烦了,我建议改为设置一个共享变量来表示当前可用资源的数量,并使用互斥锁 + 条件变量而不是信号量。那看起来像这样:
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);
// ...
}