1

类 UNIX 操作系统中的系统调用是可重入的(即可以并行执行多个系统调用)。在 C/C++11 发生之前关系的意义上,这些系统调用是否有任何排序约束?

例如,让我们考虑以下具有 3 个线程的程序(在伪代码中):

// thread 1
store x 1
store y 2

// thread 2
store y 1
store x 2

// thread 3
Thread.join(1 and 2)
wait((load x) == 1 && (load y) == 1)

在这里,假设xy是共享位置,并且所有的loadstores 都具有宽松的顺序。(注意:对于宽松的原子访问,竞态不被视为错误;它们在 C/C++11 语义的意义上是有意store x 1的。)该程序可能会终止,因为 (1) 编译器可能重新排序and store y 2,然后 (2) 执行store y 2, store y 1, store x 2, 然后store x 1, 所以 (3) 线程 3 可以同时读取x = 1y = 1

我想知道以下程序是否也可能终止。这里,在线程 1 和 2 中分别插入了一些系统调用syscall1()& :syscall2()

// thread 1
store x 1
syscall1()
store y 2

// thread 2
store y 1
syscall2()
store x 2

// thread 3
Thread.join(1 and 2)
wait((load x) == 1 && (load y) == 1)

该程序似乎无法终止。但是,在没有调用的系统调用的排序约束的情况下,我认为这个程序可能会终止。这就是原因。假设syscall1()syscall2()没有被序列化并且可以并行运行。然后,编译器在完全了解 and 的语义的情况下syscall1()syscall2()仍然可以重新排序store x 1& syscall1()and store y 2

所以我想问一下不同线程调用的系统调用是否有任何排序约束。如果可能的话,我想知道这类问题的权威来源。

4

1 回答 1

1

从用户空间中的应用程序的角度来看,系统调用(在syscalls(2) ...中列出的那些)是一种基本操作。

每个系统调用(根据定义)通过一些单一的 机器代码指令(SYSENTER,,SYSCALL... INT)调用内核;细节取决于处理器(其指令集)和 ABI。内核执行它的业务(处理您的系统调用 - 这可能成功或失败),但您的用户程序只看到一个基本步骤。有时该步骤(在此期间将控制权交给内核)可能会持续很长时间(例如几分钟或几小时)。

因此,您在用户空间中的程序在低级虚拟机中运行,由处理器的用户模式机器指令提供,并由单个“虚拟”系统调用指令(能够执行内核实现的任何系统调用)增强。

这并不禁止您的程序因为竞争条件而出现错误。

于 2016-03-26T13:13:14.777 回答