[英]Spin Lock using xchg
我正在嘗試使用xchg命令的內聯匯編在C中實現最簡單的自旋鎖(使用TAS)。 由於我的編譯器錯誤消息越來越異乎尋常,並且我開始長白發,所以我決定在這里詢問。 另外,對於這個問題,因為我什么都沒找到,所以我也很抱歉。
關於這個主題的編程經驗,可能需要說些什么。 我用C做得很好(我認為考慮標准問題)。 我也相信了解x86的基礎知識,但是當涉及到內聯匯編程序的約束時,我完全迷失了。 我發現進行谷歌搜索的做法令我更加困惑,因為許多消息來源說的東西完全不同。
到目前為止,我的代碼:
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;
}
這可能不是很明顯的原因,但是卻讓我發瘋。 我也嘗試了其他一些變體,但沒有一個被編譯。 您可能現在可以告訴我我真的不知道自己在做什么,因此我對任何建議都非常滿意。
這里是我的編譯器消息,以防萬一:
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.
提前致謝
一個絕望的學生
編輯:
我得到了鎖來工作.. do while循環,而逗號起到了作用。 現在,我有一個新問題,我的鎖實現似乎仍然不能保證排他訪問。.我將發布整個代碼,並對任何建議/批評感到高興。
#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("%d\n",x);
return 0;
}
EDIT2:
正如將整個循環鎖定在thread_do函數中時所看到的,我的鎖實際上確實起作用。 我對這個結果不太滿意,因為它鎖定了很長時間,但是我想我必須忍受這個。.我認為問題是我的asm指令與我無法保證原子性的比較之間當鎖定和解鎖是如此快速的指令流(用於thread_do中的循環)時,由於我在C語言中看不到變通方法(歡迎提出建議),我將堅持這種實現,因為總體思路似乎是正確的。
如果您嘗試進行自旋鎖,則可能需要使用強大的原子比較交換。
這是使用內置的GCC進行的acquire_lock
的簡單實現:
int acquire_lock(int* lock)
{
while (__sync_val_compare_and_swap (lock, 0, 1) != 0)
{
// Do something while waiting for the lock ?
}
return 0;
}
與內聯ASM相比,編譯器內建程序具有更具可讀性和可移植性的優勢。
關於代碼中的錯誤,您在操作數之間缺少逗號。 那條線:
__asm__("xchg %0 %1" : "+q" (val), "+m" (lock_cont));
應該 :
__asm__("xchg %0, %1" : "+q" (val), "+m" (lock_cont));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.