Я новичок в параллелизме в C и пытаюсь кое-что понять, чтобы понять, как это работает.
Я хотел написать соответствующую реализацию пинг-понга без блокировок, то есть один поток печатает ping, после этого другой поток печатает pong и делает его свободным от блокировки. Вот моя попытка:
#if ATOMIC_INT_LOCK_FREE != 2
#error atomic int should be always lock-free
#else
static _Atomic int flag;
#endif
static void *ping(void *ignored){
while(1){
int val = atomic_load_explicit(&flag, memory_order_acquire);
if(val){
printf("ping\n");
atomic_store_explicit(&flag, !val, memory_order_release);
}
}
return NULL;
}
static void *pong(void *ignored){
while(1){
int val = atomic_load_explicit(&flag, memory_order_acquire);
if(!val){
printf("pong\n");
atomic_store_explicit(&flag, !val, memory_order_release);
}
}
return NULL;
}
int main(int args, const char *argv[]){
pthread_t pthread_ping;
pthread_create(&pthread_ping, NULL, &ping, NULL);
pthread_t pthread_pong;
pthread_create(&pthread_pong, NULL, &pong, NULL);
}
Я тестировал его несколько раз, и он работал, но есть вещи, которые кажутся странными:
- Он либо заблокирован, либо не компилируется
Поскольку Стандарт определяет свойство lock-free равным 2, чтобы все операции с атомарным типом всегда были свободными от блокировки. В частности, я проверил код компиляции, и он выглядит как
sub $0x8,%rsp
nopl 0x0(%rax)
mov 0x20104e(%rip),%eax # 0x20202c <flag>
test %eax,%eax
je 0xfd8 <ping+8>
lea 0xd0(%rip),%rdi # 0x10b9
callq 0xbc0 <puts@plt>
movl $0x0,0x201034(%rip) # 0x20202c <flag>
jmp 0xfd8 <ping+8>
Это кажется нормальным, и нам даже не нужен какой-то забор, поскольку Intel CPU s не позволяет переупорядочивать хранилища с более ранними загрузками. Такие предположения работают только в том случае, если мы знаем аппаратную модель памяти, которая не является переносимой.
- Использование stdatomics с pthreads
Я застрял в glibc 2.27, где threads.h
еще не реализован. Вопрос в том, строго ли это соответствует требованиям? В любом случае это как-то странно, если у нас есть атомики, но нет потоков. В чем же тогда согласованное использование stdatomic
s в многопоточном приложении?
N1570 ISO/IEC 9899:201x
(или хорошо, если мы примем во внимание, что мы используемpthread
s наLinux
) для использованияstdatomic
s сpthread
s (или любой другой реализации потоковой передачи)? - person Some Name   schedule 10.04.2019N1570 ISO/IEC 9899:2011
и на самом деле пытаюсь понять, как использоватьstdatomic
безthreads.h
. Гарантирует ли Стандарт, что атомарное поведение должно быть четко определено со всеми реализациями потоков (например,pthread
s, erlierLinuxThread
s и т. Д.) - person Some Name   schedule 10.04.20195.1.2.3
: При размещенной реализации программа может иметь более одного потока выполнения (или потока), выполняющихся одновременно. Выполнение каждого потока продолжается, как определено в остальной части этого стандарта. не упоминается, что потоки точно изthreads.h
, но как определено в размещенной среде. Таким образом, гарантии видимости, предоставляемыеstdatomic
, также должны согласовываться сpthreads
. Разве такое рассуждение не верно? - person Some Name   schedule 10.04.2019stdatomic
s можно использовать в любое время, когда мне нужны гарантии атомарности / порядка памяти (даже еслиthreads.h
не реализованы) ... - person Some Name   schedule 10.04.2019stdatomic
должен гарантировать, что все атомарное является атомарным с точки зрения любого возможного внешнего наблюдателя (независимо от того, реализованы или используются потоки и какой тип потоков). Обратите внимание, что только для потоков вам понадобится атомарный элемент с точки зрения другого потока, который значительно слабее, чем атомарный с точки зрения любого возможного наблюдателя, который должен предоставитьstdatomic
. - person Brendan   schedule 11.04.2019