竞争状态是这样一种情形:操作共享资源的两个进程(或线程),其结果取决于一个无法预期的顺序,即这些进程获得CPU使用权的先后相对顺序。
以独占的方式创建一个文件
当同时指定了O_EXCL和O_CREAT作为open的标志位时,如果要打开的文件已经存在,则open将返回一个错误。
这种机制为了保证进程是打开文件的创建者。
对文件是否存在的检查和创建属于同一原子操作。、
如果不实用O_EXCL标志的话,要调用两次open,以此判断文件是否存在,一个是创建一个文件。
但有个情况是:
当第一次调用open时,希望打开的文件还不存在,而当第二次调用open时,其他进程已经创建了该文件。
如下图,若内核调度器判断出分配给A进程的时间片已经耗尽,并且将CPU的使用权交给B进程,就有肯能发生这种问题。
再比如两个进程在一个多CPU系统上同时运行,也会出现这种情况。
在这种情况下,A会认为目标文件是由自己创建的。因为不论目标文件存在与否,进程A对open的第二次调用都会成功。
由于第一个进程在检查文件是否存在和创建文件之间发生了中断,造成两个进程都声称自己是文件的创建者。
结合O_CREAT和O_EXCL标志来一次性地调用open可以防止这种情况,因为这确保了检查和创建文件的捕捉属于一个单一的原子(不可中断的)操作。
向文件尾部追加数据
说明原子操作的第二个例子是:多个进程文件同时同一个文件(例如,全局日志文件)尾部添加数据。
每次写入新的日志时,会用lseek将文件偏移量设置到文件尾部,然后再写入数据。
但是在lseek和write之间会被其他进程所打断,那么这两个进程在写入数据前,将文件偏移量设为相同位置,而当第一个进程再次获得调度时,会覆盖第二个进程已写入的数据。此时再次出现了竞争状态,因为执行的结果依赖于内核对两个进程的调度顺序。
要规避这一个问题,需要将文件偏移量的移动与数据写入操作纳入同一个原子操作。在打开文件时加入O_APPEND标志就可以保证这一点。
注意了,在打开文件时加入O_APPEND标志。所以这个意思就是,打开之后的写都是先移到文件末尾,在写数据咯?