c - 实现我自己的互斥锁时如何从内联汇编中引用 C 中的指针
问题描述
作为一个练习,我正在尝试实现我自己的互斥库,以便在我即将推出的 C 程序中使用。建议我为此使用内联汇编,因此为 x86 (AT&T) 生成了以下代码:
#include "mymutex.h"
void init_my_mutex(my_mutex_t *mutex){
*mutex = 1;
}
void lock_my_mutex(my_mutex_t *mutex){
asm( "movq $0, %%rax\n\t" // temp = 0
"movq $0, %%rbx\n\t"
"1: xchgq (mutex), %%rax\n\t"
"cmpq %%rax, %%rbx\n\t"
"jz 1b\n\t":::"rax","rbx");
}
void unlock_my_mutex(my_mutex_t *mutex){
*mutex = 1;
}
问题是我不知道*mutex
在asm()
里面如何正确处理lock_my_mutex
。gcc -c mymutex.c -o mymutex.o
编译得很好,但是当尝试编译我的测试程序count-primes.c
时gcc -pthread count-primes.c mymutex.o -o count-primes
,我得到以下错误relocation R_X86_64_32S against undefined symbol 'mutex' can not be used when making a PIE object; recompile with -fPIC
:我试过重新编译-fPIC
(我不知道这应该有什么帮助),但我仍然得到同样的错误。
我的头文件如下所示:
#ifndef __mymutex_h
#define __mymutex_h
// Our mutex is very simple so it is either locked
// or unlocked and we don't keep any other information
typedef long long my_mutex_t;
// Initializes a mutex to be unlocked
void init_my_mutex(my_mutex_t *mutex);
// Tries to grab a lock. The function only
// returns when the current thread holds the lock
void lock_my_mutex(my_mutex_t *mutex);
// Unlock the mutex. You don't need to check to see
// if the current thread holds the lock
void unlock_my_mutex(my_mutex_t *mutex);
#endif
在count-primes.c
中,我尝试像这样使用互斥锁:
my_mutex_t lock;
...
lock_my_mutex(&lock);
// Synchronized operation
unlock_my_mutex(&lock);
...
我怀疑这个问题与我在使用互斥锁时的地址有关,asm()
并认为理解如何(以及为什么)这样做将使我能够解决这个问题。但在任何其他方面的帮助也非常感谢。
最好的,
史蒂芬。
解决方案
要么使用内存约束,要么使用包含地址和内存破坏器的输入寄存器:
有内存限制:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm( "mov $0, %1\n\t"
"1: xchg %1,%0\n\t"
"test %1, %1\n\t"
"jz 1b\n\t": "+m(*mutex), "=&r"(tmp));
}
使用内存破坏器:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm volatile(
"mov $0, %0\n\t"
"1: xchg %0,(%1)\n\t"
"test %0, %0\n\t"
"jz 1b\n\t": "=&r"(tmp) : "r"(mutex) : "memory");
}
实际上,内存破坏器应该有任何一种方式来模拟这样一种想法,即由于与其他线程同步,其他对象的值可能会在编译器背后发生变化(受互斥锁保护的对象)。我更喜欢后一种方法,因为它并不意味着如果不再访问互斥对象,则可以删除 asm。
请注意,您可以通过以下方式进一步摆脱 mov:
void lock_my_mutex(my_mutex_t *mutex){
uint64_t tmp;
asm volatile(
"1: xchg %0,(%1)\n\t"
"test %0, %0\n\t"
"jz 1b\n\t": "=&r"(tmp) : "r"(mutex), "0"(0) : "memory");
}
FWIW 我会称您编写的内容为自旋锁(一个非常糟糕的主意),而不是互斥锁。
推荐阅读
- python - 类型错误:对象类型
不能传递给 C 代码 - javascript - 如何在 JavaScript 中添加/附加所有函数调用的结果
- c# - Windows 服务和系统文件观察器
- javascript - Shuffle.js - 在页面加载时过滤图像
- node.js - Rest api - 连接到数据库和服务器 - 不推荐使用 URL 字符串解析器
- java - 如何在验证来自客户端的 JSON 输入时获取“违反约束列表”?
- javascript - 通过减小字体大小和截断文本来适应容器内的文本
- python - 如何隐藏 Django Chartit 图表的 xAxis 和 yAxis 标题?
- java - ThreadPoolTaskScheduler 在运行时更改 poolSize
- php - Laravel 在所有 api 路由中使用 Web 身份验证重定向到主页