Linux中的两种文件锁—协同锁与强制锁

fmms 13年前
     <p>        英文原文:<a href="/misc/goto?guid=4958337816986486563">2 Types of Linux File Locking (Advisory, Mandatory Lock Examples)</a></p>    <p>        文件锁是一种文件读写机制,在任何特定的时间只允许一个进程访问一个文件。利用这种机制能够使读写单个文件的过程变得更安全。</p>    <p>        在这篇文章中,我们将探讨 Linux 中不同类型的文件锁,并通过示例程序来理解它们之间的不同之处。</p>    <p>        我们将采取以下的例子来解释为什么需要使用文件锁。</p>    <p>        1、  进程“A”打开和读取一个文件,此文件包含账户相关的一些信息。</p>    <p>        2、  进程“B”也打开了这个文件,并读取了文件中的信息。</p>    <p>        3、  现在,进程“A”更改了其副本中的一条余额记录,并将其写入文件。</p>    <p>        4、  此时,进程“B”并不知道上次读取的文件已经被更改,它还保存着原始的文件副本。然后,进程“B”更改了“A”操作的那条相同的记录,并将记录写入文件。</p>    <p>        5、  此时,文件中将只保存了进程“B”更改过的记录。</p>    <p>        为了避免这种事情发生,就要使用文件锁来确保操作的“序列化”。</p>    <p>        以下是 Linux 系统中两种常用的文件锁:</p>    <p>        1、  协同锁</p>    <p>        2、  强制锁</p>    <p style="text-align:center;"><a title="2 Types of Linux File Locking" rel="lightbox[16882]"><img title="2 Types of Linux File Locking" alt="Linux中的两种文件锁—协同锁与强制锁" src="https://simg.open-open.com/show/9340ded8023ddf62d96c4957f3303912.jpg" width="316" height="428" /></a></p>    <p>        <strong>1、  协同锁</strong></p>    <p>        协同锁要求参与操作的进程之间协同合作。假设进程“A”获得一个 WRITE 锁,并开始向文件中写入内容;此时,进程“B”并没有试图获取一个锁,它仍然可以打开文件并向文件中写入内容。在此过程中,进程“B”就是一个非合作进 程。如果进程“B”试图获取一个锁,那么整个过程就是一个合作的过程,从而可以保证操作的“序列化”。</p>    <p>        只有当参与操作的进程是协同合作的时候,协同锁才能发挥作用。协同锁有时也被称为“非强制”锁。</p>    <p>        <strong>2、  强制锁</strong></p>    <p>        强制锁不需要参与操作的进程之间保持协同合作。它利用内核来查检每个打开、读取、写入操作,从而保证在调用这些操作时不违反文件上的锁规则。关于强制锁的更多信息,可以在 <a href="/misc/goto?guid=4958337817789953775" rel="nofollow" target="_blank">kernal.org</a> 上找到。</p>    <p>        为了使能 Linux 中的强制锁功能,你需要在文件系统级别上打开它,同时在单个文件上打开它。其步骤是:</p>    <p>        1、  挂载文件系统时使用“-o mand”参数。</p>    <p>        2、  对于要打开强制锁功能的文件 lock_file,必须打开 set-group-ID 位,关闭 group-execute 位。(选择此方法的原因是,当你关闭 group-execute 时,设置 set-group-ID 就没有实际的意义了)</p>    <p>        <strong>Linux 文件锁的示例</strong></p>    <p>        为了理解文件锁是如何工作的,我们建立程序文件 file_lock.c:</p>    <div class="cnblogs_code">     <pre>#include           <stdio.h>              #include             <fcntl.h>                 <span style="color:#0000ff;">int</span> main (              <span style="color:#0000ff;">int</span> argc,               <span style="color:#0000ff;">char</span> **argv) {                  <span style="color:#0000ff;">if</span> (argc >               <span style="color:#800080;">1</span>) {                    <span style="color:#0000ff;">int</span> fd = open (argv[              <span style="color:#800080;">1</span>], O_WRONLY);                    <span style="color:#0000ff;">if</span>(fd == -              <span style="color:#800080;">1</span>) {        printf (              <span style="color:#800000;">"</span>              <span style="color:#800000;">Unable to open the file\n</span>              <span style="color:#800000;">"</span>);        exit (              <span style="color:#800080;">1</span>);      }                    <span style="color:#0000ff;">static</span>               <span style="color:#0000ff;">struct</span> flock               <span style="color:#0000ff;">lock</span>;                       <span style="color:#0000ff;">lock</span>.l_type = F_WRLCK;                    <span style="color:#0000ff;">lock</span>.l_start = ;                    <span style="color:#0000ff;">lock</span>.l_whence = SEEK_SET;                    <span style="color:#0000ff;">lock</span>.l_len = ;                    <span style="color:#0000ff;">lock</span>.l_pid = getpid ();                       <span style="color:#0000ff;">int</span> ret = fcntl (fd, F_SETLKW, &              <span style="color:#0000ff;">lock</span>);      printf (              <span style="color:#800000;">"</span>              <span style="color:#800000;">Return value of fcntl:%d\n</span>              <span style="color:#800000;">"</span>,ret);                    <span style="color:#0000ff;">if</span>(ret==) {                      <span style="color:#0000ff;">while</span> (              <span style="color:#800080;">1</span>) {          scanf (              <span style="color:#800000;">"</span>              <span style="color:#800000;">%c</span>              <span style="color:#800000;">"</span>, NULL);        }      }    }  }            </fcntl.h>          </stdio.h></pre>    </div>    <p style="text-align:left;">        用 gcc 编译此程序:</p>    <div class="cnblogs_code">     <pre># cc -o file_lock file_lock.c</pre>    </div>    <p style="text-align:left;">        使用 mount 命令带“mand”参数来重新挂载根文件系统,如下所示。这将在文件系统级别使能强制锁功能。<strong>注意:</strong>你必须切换到 root 用户才能执行下面的命令。</p>    <div class="cnblogs_code">     <pre># mount -oremount,mand /</pre>    </div>    <p style="text-align:left;">        在可执行的(file_lock 所在的)目录中创建两个名为“advisory.txt”和“mandatory.txt”的文件。对于“mandatory.txt”使能 Set-Group-ID,同时不使能 Group-Execute-Bit,如下所示:</p>    <div class="cnblogs_code">     <pre># touch advisory.txt  # touch mandatory.txt  # chmod g+s,g-x mandatory.txt</pre>    </div>    <p><strong>        测试协同锁:</strong>执行示例程序,以“advisory.txt”作为参数。</p>    <div class="cnblogs_code">     <pre># ./file_lock advisory.txt</pre>    </div>    <p>        此程序将等待用户的输入。从另一个终端或控制台,尝试输入以下命令行:</p>    <div class="cnblogs_code">     <pre># ls >>advisory.txt</pre>    </div>    <p>        在上面的例子中,ls 命令会将其输出写入到 advisory.txt 文件中。即使我们获得了一个写入锁,仍然会有一些进程(非合作)能够往文件里写入数据。这就是所谓的“协同”锁。</p>    <p>        <strong>测试强制锁:</strong>再次执行示例程序,以“mandatory.txt”作为参数。</p>    <div class="cnblogs_code">     <pre># ./file_lock mandatory.txt</pre>    </div>    <p>        从另一个终端或控制台,尝试输入以下命令行:</p>    <div class="cnblogs_code">     <pre># ls >>mandatory.txt</pre>    </div>    <p>        在上面的例子中,ls 命令在将其输出写入到 mandatory.txt 文件之前,会等待文件锁被删除。虽然它仍然是一个非合作进程,但强制锁起了作用。</p>    <p>        英文原文:<a href="/misc/goto?guid=4958337816986486563" rel="nofollow" target="_blank">Lakshmanan Ganapathy</a>    编译:<a title="伯乐在线" href="/misc/goto?guid=4958185140659301754" target="_blank">伯乐</a>在线 – <a href="/misc/goto?guid=4958337820047243751" target="_blank">肖翔</a></p>