我有关于编译器更改执行顺序的问题。我试图通过用信号机制(thorugh 信号量)替换临界区来提高多线程程序(C 语言)的性能。
我这里需要保证执行顺序,一直在研究这个。我看到很多关于函数内执行顺序的问题,但很少讨论函数内的函数。
基于 https://en.wikipedia.org/wiki/Sequence_point规则 #4,下面的代码块是否保证 *p->a
必须在输入 func2
之前首先被评估,因为 func2
将 p
作为输入(假设编译器遵守此处定义的调度点规则)?
func1 (struct *p) {
p->a = x;
func2 (p);
}
func2 (struct *p) {
p->b = y;
releaseSemaphore(s);
}
重要的是p->b
只有在设置了p->a
之后才设置,因为另一个线程在循环中处理各种请求并识别有效请求通过是否设置了p->b
。释放信号量只会在任务空闲(等待信号量)时触发任务,但如果它正忙于处理其他请求,它会稍后检查p->b
,我们不能保证func1
仅在该线程空闲时调用。
最佳答案
没有。序列点排序不会跨越线程边界。这就是为什么我们首先需要内存排序保证的全部要点。
对于执行代码的线程,始终保证序列点排序(模假设规则)。任何其他 线程可能会以任意顺序观察该线程的写入。这意味着即使线程 #1 可以验证它以特定顺序执行写入,线程 #2 仍可能以不同的顺序观察它们。这就是为什么 volatile 在这里也是不够的。
从技术上讲,这可以解释为例如。通过缓存。线程 #1 的写入可能首先进入写入缓冲区,线程 #2 仍然看不到它们。只有当写入缓冲区被刷新回主内存时,它们才会变得可见,并且允许硬件在刷新之前对写入重新排序。
请注意,仅仅因为平台被允许重新排序写入并不意味着它会这样做。这是危险的部分。在一个平台上运行良好的代码在移植到另一个平台时可能会突然出现。使用正确的内存顺序可确保代码无处不在。
关于c - 在不使用 volatile 或内存屏障和锁的情况下保证执行顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42713383/