根据这个cppreference page,对于_Atomic int a
,++a
/a++
/a %= 2
/etc都是原子的。但问题是,将下面的表达式:
_Atomic size_t thread_counter = 0;
void thread_counting() {
int execution_id = (thread_counter++) % THREAD_NUM;
}
字符串
就像使用mutex
?实现一样“原子”:
pthread_mutex_t my_mutex;
size_t thread_counter = 0;
void thread_counting() {
pthread_mutex_lock(&my_mutex); // assume pthread_mutex_lock() always success
int execution_id = (thread_counter++) % THREAD_NUM;
pthread_mutex_unlock(&my_mutex);
}
型
C11标准的措辞对我来说有点太深奥了,我没能从中得到一个具体的答案。我准备了下面的代码来测试这个假设,结果似乎表明答案是肯定的,但不确定其中是否有什么大的缺陷。
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define THREAD_NUM 5000
#define PASS_NUM 128
_Atomic uint8_t *table = NULL;
_Atomic size_t thread_counter = 0;
_Atomic short error = 0;
void *counting(void *pass) {
uint8_t p = *((uint8_t *)pass);
if (error) {
return NULL;
}
int execution_id = (thread_counter++) % THREAD_NUM;
// Alternative implementation, breaks atomicity:
// thread_counter = (thread_counter + 1) % THREAD_NUM;
// int execution_id = thread_counter;
if (table[execution_id] == p) {
table[execution_id] = p + 1;
} else {
fprintf(stderr, "ERROR: table[%d]==%u, expecting %u\n", execution_id,
table[execution_id], p);
++error;
}
return NULL;
}
void test_concurrent_counting() {
table = (_Atomic uint8_t *)calloc(THREAD_NUM, sizeof(short));
if (table == NULL) {
perror("calloc()");
goto err_calloc_table;
}
pthread_t *ths = (pthread_t *)calloc(THREAD_NUM, sizeof(pthread_t));
if (table == NULL) {
perror("malloc()");
goto err_malloc_pthread;
}
for (uint8_t i = 0; i < PASS_NUM && error == 0; ++i) {
printf("Pass no.%u\n", i);
int j = 0;
for (; j < THREAD_NUM; ++j) {
if (pthread_create(&ths[j], NULL, counting, &i) != 0) {
// this error handling might not be perfect
--j;
perror("pthread_create()");
break;
}
}
for (int k = 0; k <= j; ++k) {
(void)pthread_join(ths[k], NULL);
}
}
free(ths);
err_malloc_pthread:
free(table);
err_calloc_table:
return;
}
int main(void) {
test_concurrent_counting();
return 0;
}
型
1条答案
按热度按时间ujv3wf0j1#
如果
THREAD_NUM
是常量,那么您的代码是线程安全的。字符串
execution_id
-是一个局部变量,所以它不会在线程之间共享。而对共享变量thread_counter
的thread_counter++
操作是由_Atomic
声明的原子操作,因此并发线程不会看到它部分执行。所以它相当于
型