/ / Spin Lock za pomocą xchg - c, x86, blokowanie

Spin Lock przy użyciu xchg - c, x86, locking

Próbuję wprowadzić najprostszy spinlock(używając TAS) w C używając wbudowanego zestawu za pomocą polecenia xchg. Ponieważ moje komunikaty o błędach kompilatora stają się coraz bardziej egzotyczne i zaczynam rosnąć siwymi włosami, zdecydowałem się tutaj zapytać. Również przepraszam, jeśli to pytanie zostało już odebrane, ponieważ niczego nie znalazłem.

Co trzeba powiedzieć o moim programowaniudoświadczenie dotyczące tego tematu. Radzę sobie całkiem dobrze z C (moim zdaniem, biorąc pod uwagę standardowe problemy) .Myślę również, że znam podstawy dotyczące x86, ale jestem całkowicie zagubiony, jeśli chodzi o ograniczenia w asembler linii. To, co znalazłem, robiąc trochę googlowania, jest dla mnie jeszcze bardziej mylące, ponieważ wiele źródeł mówi bardzo różne rzeczy.

Mój dotychczasowy kod:

int acquire_lock(int* lock){
int val = 1;
int lock_cont;
while((lock_cont = *lock) != 0){
__asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));
}
return 0;
}

To nie działa z powodów, które są prawdopodobnieTo oczywiste, ale sprawiasz, że tracę rozum. Próbowałem także innych wariantów, ale żaden z nich nie był nawet skompilowany, prawdopodobnie możesz już powiedzieć, że nie wiem, co robię, więc byłbym bardziej niż szczęśliwy z powodu jakiejkolwiek porady.

Oto moje komunikaty kompilatora, na wypadek gdyby to pomogło:

my_lock.c:17:11: error: unexpected token in argument list
__asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));
^
<inline asm>:1:12: note: instantiated into assembly here
xchg %eax -16(%rbp)
^
1 error generated.

Z góry dziękuję

Zdesperowany student

EDYTOWAĆ:

Mam blokadę do pracy ... pętla do zrobienia, a przecinek zrobił lewy. Teraz mam nowy problem, że moja implementacja blokady nadal nie gwarantuje wyłącznego dostępu. Zamieszczam cały kod i będę szczęśliwy z wszelkich sugestii / krytyków.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

//shared variable
int x;

//new lock instance that"s consistent over function calls
int* new_lock(){
int* ptr = (int*)(malloc(sizeof(int)));
*ptr = 0;
return ptr;
}

//set content of lock atomically to 1
int acquire_lock(int* lock){
int val = 1;
do{
__asm__("xchg %0, %1" : "+q" (val), "+m" (*lock));
}while(val - (*lock) == 0);
return 0;
}

//release the lock
int release_lock(int* lock){
*lock = 0;
return 0;
}

//free lock
int delete_lock(int* ptr){
free(ptr);
return 0;
}

//thread counts to 10^6
void* thread_do(void* arg){
int* lock = (int*) arg;
for(int i = 0; i < 100000; i++){
acquire_lock(lock);
x++;
release_lock(lock);
}
return NULL;
}

int main(int argc, char** argv){
pthread_t thread0, thread1;
int* lock = new_lock();
pthread_create(&thread0, NULL, thread_do, lock);
pthread_create(&thread1, NULL, thread_do, lock);
pthread_join(thread0, NULL);
pthread_join(thread1, NULL);
printf("%dn",x);
return 0;
}

EDIT2:

Mój zamek rzeczywiście działa, jak widać, kiedyblokowanie całej pętli wewnątrz funkcji thread_do. Nie całkiem zadowolony z tego wyniku, ponieważ blokuje x przez dość długi czas, ale myślę, że będę musiał z tym żyć. Zakładam, że problem polega na tym, że pomiędzy moją instrukcją asm a porównaniem od chwili, gdy nie mogę zagwarantować atomowości kiedy blokowanie i odblokowywanie jest takim szybkim strumieniem instrukcji (dla pętli w thread_do), ponieważ nie widzę obejścia w C (sugestie są mile widziane), będę trzymać się tych implementacji, ponieważ ogólny pomysł wydaje się być właściwy.

Odpowiedzi:

2 dla odpowiedzi № 1

Jeśli próbujesz zrobić spinlock, prawdopodobnie będziesz chciał użyć silnej wymiany porównania atomów.

Oto prosta realizacja ciebie acquire_lock używając wbudowanego GCC:

int acquire_lock(int* lock)
{
while (__sync_val_compare_and_swap (lock, 0, 1) != 0)
{
// Do something while waiting for the lock ?
}
return 0;
}

Wbudowane kompilatory mają tę zaletę, że są bardziej czytelne i nieco bardziej przenośne niż wbudowane ASM.


/>

Jeśli chodzi o błąd w twoim kodzie, brakuje ci przecinka między operandami. Ta linia:

__asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));

Powinno być :

__asm__("xchg %0, %1" : "+q" (val), "+m" (lock_cont));