我只想让我的代码尽可能简单并且线程安全。SPSC螺纹安全栅栏
随着C11原子学
关于部分ISO/IEC 9899/201X草案
X和Y的 “7.17.4栅栏”,在某些原子物体M两种操作,使得A是 在X之前测序,X修改M,Y在B之前测序,且Y读取由X写入的值或由 假设版本序列X中的任何副作用写入的值如果它是版本 操作。
此代码是否线程安全(将“w_i”作为“对象M”)?
“w_i”和“r_i”是否都需要声明为_Atomic?
如果只有w_i是_Atomic,那么主线程是否可以在缓存中保留r_i的旧值并将队列视为未满(填满时)并写入数据?
如果我读了一个没有atomic_load的原子,怎么回事?
我做了一些测试,但所有的尝试似乎都给出了正确的结果。但是,我知道我的测试对于多线程来说并不是真的正确:我多次运行程序并查看结果。
即使既不将w_i不是r_i声明为_Atomic,我的程序也可以正常工作,但是对于C11标准,只有围栏是不够的,对吧?
typedef int rbuff_data_t;
struct rbuf {
rbuff_data_t * buf;
unsigned int bufmask;
_Atomic unsigned int w_i;
_Atomic unsigned int r_i;
};
typedef struct rbuf rbuf_t;
static inline int
thrd_tryenq(struct rbuf * queue, rbuff_data_t val) {
size_t next_w_i;
next_w_i = (queue->w_i + 1) & queue->bufmask;
/* if ring full */
if (atomic_load(&queue->r_i) == next_w_i) {
return 1;
}
queue->buf[queue->w_i] = val;
atomic_thread_fence(memory_order_release);
atomic_store(&queue->w_i, next_w_i);
return 0;
}
static inline int
thrd_trydeq(struct rbuf * queue, rbuff_data_t * val) {
size_t next_r_i;
/*if ring empty*/
if (queue->r_i == atomic_load(&queue->w_i)) {
return 1;
}
next_r_i = (queue->r_i + 1) & queue->bufmask;
atomic_thread_fence(memory_order_acquire);
*val = queue->buf[queue->r_i];
atomic_store(&queue->r_i, next_r_i);
return 0;
}
我把论文的功能如下:
主线程入队的一些数据:
while (thrd_tryenq(thrd_get_queue(&tinfo[tnum]), i)) {
usleep(10);
continue;
}
其他线程出列数据:
static void *
thrd_work(void *arg) {
struct thrd_info *tinfo = arg;
int elt;
atomic_init(&tinfo->alive, true);
/* busy waiting when queue empty */
while (atomic_load(&tinfo->alive)) {
if (thrd_trydeq(&tinfo->queue, &elt)) {
sched_yield();
continue;
}
printf("Thread %zu deq %d\n",
tinfo->thrd_num, elt);
}
pthread_exit(NULL);
}
使用ASM围栏
关于与lfence和SFENCE, 特定平台的x86如果我删除所有的C11代码,只是通过
asm volatile ("sfence" ::: "memory");
和
asm volatile ("lfence" ::: "memory");
代替栅栏(我的这些宏观的理解是:编译篱笆以防止内存访问被reoganized /优化+硬件围栏)
我的变量是否需要声明为volatile?
我已经看过上面这个环形缓冲区代码,只有这些asm的栅栏,但没有原子类型,我真的很惊讶,我想知道这段代码是否正确。
谢谢!如果我避免使用围墙,我必须使用atomic_store_explicit和所需的内存顺序?或者我只写:queue-> w_i = next_w_i(这是默认使用的放松顺序?) 在哪种情况下我应该使用fence? – treywelsh
不,默认顺序是顺序一致性,最强可能。 –