【发布时间】:2014-04-20 21:04:34
【问题描述】:
我想在汇编中使用“TSL”指令,但它没有参考理解。在某些文章中,该指令是针对互斥问题引入的,但没有参考或完整的示例来完全理解。
【问题讨论】:
-
它适用于什么平台?这种功能通常有高级包装器。在 Windows 中,有一堆 InterlockedXXXX 操作。在 GCC 中,有内置函数。除非必要,否则不要重新发明同步原语。
我想在汇编中使用“TSL”指令,但它没有参考理解。在某些文章中,该指令是针对互斥问题引入的,但没有参考或完整的示例来完全理解。
【问题讨论】:
TSL(Test and Set Lock)是在处理一般互斥问题时经常出现的操作,但这并不意味着这样的指令实际上存在于您使用的任何架构上;或者,即使它确实存在,它也被称为 TSL。
例如,在 x86 上,您可以使用 XCHG 指令来执行 TSL。
【讨论】:
MOV EAX, 1; XCHG EAX, [lock]
XCNG 不是有条件的,它只是用一个内存位置交换一个寄存器。您想要的是带有 LOCK 前缀的 CMPXCHG。后者将使其在多核机器上具有原子性。
此外,您可以使用 LOCK XADD 实现原子比较和设置,但这需要一个循环。
【讨论】:
for example,所以还有其他方法可以做到这一点,但除非你能证明,否则我的方法并没有错。另请参阅wikipedia。
我认为@Jester 和@Seva Alekseyev 已经在回答这个问题方面做得很好,但这里是一个简单的 C 语言实现,通过在 x86 Ubuntu 机器上使用 pthreads 实现。
在以下示例中,有两个长时间运行的线程。两个线程都有一个临界区和一个非临界区,分别是critical_region() 和noncritical_region。他们都必须调用 enter_region() 才能获得锁。一旦线程获得锁,它就可以开始运行它的临界区。另一个线程被阻塞,直到有锁的线程调用leave_region()。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
void enter_region() {
asm(
".data\n\t"
"lock:\n\t"
".byte 0\n\t"
".text\n\t"
"_enter_region:\n\t"
"movb $1, %al\n\t" /* move 1 to AL */
"xchgb (lock),%al\n\t"
"cmp $0, %al\n\t"
"jne _enter_region\n\t"
);
}
void leave_region() {
asm("movb $0, (lock)");
}
void critical_region() {
}
void noncritical_region() {
}
static void* f1(void* p) {
while(1) {
puts("wait for f2");
enter_region();
printf("f1 can start its critical section\n");
critical_region();
leave_region();
noncritical_region();
}
return NULL;
}
static void* f2(void* p) {
while(1) {
puts("wait for f1");
enter_region();
printf("f2 can start its critical section\n");
critical_region();
leave_region();
/* if you call sleep, you can see that the non-critical section of this thread won't
* block the other thread from running its critical section as many times as it wants
*/
// sleep(1);
noncritical_region();
}
return NULL;
}
int main() {
int rc;
pthread_t t1, t2;
rc = pthread_create(&t1, NULL, f1, NULL);
if(rc != 0) {
fprintf(stderr, "pthread f1 failed\n");
return EXIT_FAILURE;
}
rc = pthread_create(&t2, NULL, f2, NULL);
if(rc != 0) {
fprintf(stderr, "pthread f2 failed\n");
return EXIT_FAILURE;
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
puts("All threads finished.");
return 0;
}
【讨论】: