三)强制性加锁的实现
1)对文件加锁有两种方式:劝告性锁和强制性锁.
2)劝告性锁工作时,每个进程都要对文件进行读或写之前调用lockf对文件加锁,如果一个进程忘记调用lockf,那么锁协议将会被忽视
3)强制性锁工作时,它将使任何一个想要访问已被加锁的文件的进程都堵塞在读或写队列上.加锁的过程是由内核强制启动的,所以不用担心不同步的进程忽视劝告性锁.
4)程序2就是劝告性锁的典型例子,而下面的例子会演示强制性锁的使用.
mount -o remount,rw,mand /dev/sdb1 /mnt/
cd /mnt/
chmod g-x messagebuf.dat
chmod g+s messagebuf.dat
修改程序2的源代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <sys/stat.h>
const char *filename = "messagebuf.dat";
void error_out(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void child(void)
{
FILE *fp = fopen(filename, "r+");
if (fp == NULL)
error_out("child:fopen");
/*int r = lockf(fileno(fp), F_LOCK, 0);
if (r == -1)
error_out("parent:lockf");*/
char buf[32];
fread(buf,sizeof(buf), 1, fp);
if (ferror(fp))
error_out("fread");
printf("child read '%s'\n", buf);
}
void parent(FILE *fp)
{
fprintf(fp, "%#x", getpid());
fflush(fp);
int r = lockf(fileno(fp), F_ULOCK, 0);
if (r == -1)
error_out("lockf:F_ULOCK");
fclose(fp);
}
int main(int argc, char *argv[])
{
int r;
int fd = open(filename, O_CREAT|O_TRUNC|O_RDWR, 0666);
FILE *fp = fdopen(fd, "r+");
if (fp == NULL)
error_out("parent:fopen");
r = lockf(fileno(fp), F_LOCK, 0);
if (r == -1)
error_out("parent:lockf");
pid_t pid = fork();
if (pid == 0){
child();
exit(0);
}
else{
int status = 0;
parent(fp);
wait(&status);
printf("child status=%d\n", WEXITSTATUS(status));
}
exit(0);
}
gcc file-ipc-better.c -o file-ipc-better
./file-ipc-better
child read '0x9a0'
child status=0
我们注释掉了子进程的lockf函数的过程,这时如果没有强制锁,子进程的读操作,将会忽视父进程的lockf,而我们加了强制锁,子进程的读操作被阻塞了.
最终的结果同第二个程序一样,但我们却使用了不同的锁机制.
最后使用文件进行传递媒介就意味着你可能遇到媒介中存在的潜在不安全因素.