首页 > 解决方案 > xv6: reading ticks directly without taking the ticks lock?

问题描述

I'm working on an assignment in operating system course on Xv6. I need to implement a data status structure for a process for its creation time, termination time, sleep time, etc...

As of now I decided to use the ticks variable directly without using the tickslock because it seems not a good idea to use a lock and slow down the system for such a low priority objective.

Since the ticks variable only used like so: ticks++, is there a way where I will try to retrieve the current number of ticks and get a wrong number?

I don't mind getting a wrong number by +-10 ticks but is there a way where it will be really off. Like when the number 01111111111111111 will increment it will need to change 2 bytes. So my question is this, is it possible that the CPU storing data in stages and another CPU will be able to fetch the data in that memory location between the start and complete of the store operation?

So as I see it, if the compiler will create a mov instruction or an inc instruction, what I want to know is if the store operation can be seen between the start and end of it.

标签: cassemblyx86atomicxv6

解决方案


在 asm 中没有问题:在 x86 上使用单个指令完成的对齐加载/存储是原子的,最高可达 qword(8 字节)宽度。 为什么在 x86 上对自然对齐的变量进行整数赋值是原子的?

(在 486 上,保证仅适用于 4 字节对齐的值,甚至可能不适用于 386,所以这可能就是 Xv6 使用锁定的原因?我不确定它在 386 上是否应该是多核安全的;我的理解是罕见的 386 SMP 机器并没有完全实现现代 x86 内存模型(内存排序等)。)

但是C不是asm。 一次使用来自多个“线程”的普通非atomic变量是未定义的行为,除非所有线程都只是在读取。这意味着编译器可以假设普通 C 变量不会被其他线程异步更改。

在 C 中使用ticks循环将使编译器读取一次并重复使用相同的值。你需要一个READ_ONCE像 Linux 内核使用的宏,例如*(volatile int*)&ticks. 或者简单地将其声明为volatile unsigned ticks;


对于一个足够窄以适合一个整数寄存器的变量,可以安全地假设一个理智的编译器将使用单个 dword 存储来编写它,无论是 amov或 memory-destinationinc还是add dword [mem], 1. (但是,您不能假设编译器将使用内存目标 inc/add,因此对于中断,您不能依赖于单核原子增量。)

对于一个作者和多个读者,是的,读者可以简单地阅读它,而无需任何类型的锁定,只要他们使用volatile.

即使在可移植的ISO C 中,volatile sig_atomic_t当由信号处理程序编写并由运行信号处理程序的线程读取时,也有一些非常有限的安全工作保证。(但不一定是其他线程:在 ISO Cvolatile中并不能避免数据竞争 UB。但实际上在带有非敌对编译器的 x86 上这很好。)

(POSIX 信号相当于用户空间的中断。)

另请参阅num++ 是否可以是“int num”的原子?

对于一个线程将更宽的计数器分成两半发布,您通常会使用 SeqLock。对于 1 个写入器和多个读取器,没有实际的锁定,如果写入与读取重叠,读取器只需重试。请参阅使用 32 位原子实现 64 位原子计数器


推荐阅读