【发布时间】:2016-07-05 18:46:34
【问题描述】:
我在考虑如何使用尽可能少的 asm 代码来实现信号量(不是二进制)。
在不使用互斥锁的情况下,我无法成功地思考和编写它,所以这是迄今为止我能做的最好的事情:
全球:
#include <stdlib.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
typedef struct
{
atomic_ullong value;
pthread_mutex_t *lock_op;
bool ready;
} semaphore_t;
typedef struct
{
atomic_ullong value;
pthread_mutex_t lock_op;
bool ready;
} static_semaphore_t;
/* use with static_semaphore_t */
#define SEMAPHORE_INITIALIZER(value) = {value, PTHREAD_MUTEX_INITIALIZER, true}
功能:
bool semaphore_init(semaphore_t *semaphore, unsigned long long init_value)
{
if(semaphore->ready) if(!(semaphore->lock_op = \
calloc(1, sizeof(pthread_mutex_t)))) return false;
else pthread_mutex_destroy(semaphore->lock_op);
if(pthread_mutex_init(semaphore->lock_op, NULL))
return false;
semaphore->value = init_value;
semaphore->ready = true;
return true;
}
bool semaphore_wait(semaphore_t *semaphore)
{
if(!semaphore->ready) return false;
pthread_mutex_lock(&(semaphore->lock_op));
while(!semaphore->value) __asm__ __volatile__("nop");
(semaphore->value)--;
pthread_mutex_unlock(&(semaphore->lock_op));
return true;
}
bool semaphore_post(semaphore_t *semaphore)
{
if(!semaphore->ready) return false;
atomic_fetch_add(&(semaphore->value), (unsigned long long) 1);
return true;
}
是否可以仅使用几行、使用原子内置函数或直接在汇编中实现信号量(例如lock cmpxchg)?
查看<semaphore.h> 包含的<bits/sempahore.h> 中的sem_t 结构,在我看来,它选择了一条非常不同的路径...
typedef union
{
char __size[__SIZEOF_SEM_T];
long int __align;
} sem_t;
更新:
@PeterCordes 提出了一个绝对更好的解决方案,使用原子,没有互斥体,直接对信号量值进行检查。
我仍然想更好地了解在性能方面改进代码的机会,利用内置暂停函数或内核调用避免 CPU 浪费,等待关键资源可用。
如果有一个标准的互斥锁和非二进制信号量的实现来进行比较也很好。
来自futex(7) 我读到:“Linux 内核提供 futexes(“快速用户空间互斥锁”)作为快速用户空间锁定和信号量的构建块。Futexes 非常基础,非常适合构建更高级别的锁定抽象,例如互斥锁、条件变量、读写锁、屏障和信号量。”
【问题讨论】:
-
我看不出你在哪里包含
stdatomics。不清楚你想完成什么。 -
您当然可以使用原子操作来进行值比较。但是您仍然需要内核支持来暂停和唤醒进程。除非你做一个繁忙的循环,这不是一个可行的通用解决方案。
-
@Olaf 我想在代码大小和速度方面找到最有效的方法来自己实现非二进制信号量。
-
@kaylum 我想我不能只用一个比较操作来做到这一点,因为当
value < nthreads时 n 个线程可以通过非空检查并使值变为负数,所以,正如你所说,我需要自动检查和递减,为此我使用了互斥锁。至于忙循环/等待,我虽然是 mutex_lock 所做的。您是说没有更有效和更优雅的方法来实现这一点? -
@JumpAlways "至于忙循环/等待我虽然是 mutex_lock 所做的," 绝对不是!现实世界的低级同步原语是由具有深厚平台知识的人编写的。有十几种方法可以使大多数程序员甚至不知道存在这种错误。有关类似问题的更多信息,请参阅here。你可以天真地生产一个玩具,但不要自欺欺人地认为你会得到好的表现。并且不要认为您可以轻松编写一个基准来区分好坏,因为这也很难。
标签: c multithreading assembly mutex semaphore