当两个进程都要读写一个文件的时候, 需要用读写锁。 代码:
//具体的细节和原理可以参阅 《unix advanced programming 》 里面 12章 高级I/O, 记录锁一节
int lock_reg(int fd, int cmd, int type,off_t offset, int whence, off_t len) { struct flock lock; lock.l_type = type; lock.l_start = offset; lock.l_whence = whence; lock.l_len = len; return fcntl(fd,cmd,&lock); }
#define read_lock(fd,offset,whence,len) \ lock_reg(fd,F_SETLK, F_RDLCK,offset,whence,len) #define readw_lock(fd,offset,whence,len) \ lock_reg(fd,F_SETLKW, F_RDLCK,offset,whence,len) #define write_lock(fd,offset,whence,len) \ lock_reg(fd,F_SETLK, F_WRLCK,offset,whence,len) #define writew_lock(fd,offset,whence,len) \ lock_reg(fd,F_SETLKW, F_WRLCK,offset,whence,len) #define un_lock(fd,offset,whence,len) \ lock_reg(fd,F_SETLK, F_UNLCK,offset,whence,len)
|
例子:实现一个函数操作文件: /** Read the @job_conf , search the entry same as @job , if yes , update the entry with @job otherwise append the @job at the end of the @job_conf flag : JOB_DEL : Delete the record in download_job.conf JOB_UPDATE: update the record with new DownloadConf structure return: 0:success 这里要用到writer lock ,表面上是读job_conf ,但是实际上读完之后,就要彻底更新job_conf,所以应视为写操作 **/ int UpdateJob(const DownloadJob *job ,int flag , const char *job_conf) { FILE *fp = NULL; FILE *fp_new = NULL; DownloadJob job_info ; DownloadJob *job_ptr = &job_info; int fd = 0; //ready update the JOB_CONF 's item
fp = fopen(JOB_CONF,"r+"); //其实这里主要是读,但是为了实现独占,所以用r+,配合使用writew_lock()(它要求fd是写打开的)
if(!fp) { if(flag != JOB_DEL) { fp = fopen(JOB_CONF,"w"); fd = fileno(fp); //lockf(fd,F_LOCK,0);
writew_lock(fd,0,SEEK_SET,0); fwrite(job,sizeof(DownloadJob),1,fp); //lockf(fd,F_ULOCK,0);
un_lock(fd,0,SEEK_SET,0); fclose(fp); } } else { char buf[128]; int isFound = 0; memset(buf,'\0',sizeof(buf)); fd = fileno(fp); //lockf(fd,F_LOCK,0);
//jprintf(" ============================== in UpdateJob function ==============================\n");
//jprintf("UpdateJob is waiting for writer lock \n");
writew_lock(fd,0,SEEK_SET,0); //sleep(10); //这里仅仅给客户演示 读者写者锁确实奏效而已!测试表明,读写者锁效率非常高!bob 2006-5-4 18:04
//jprintf("UpdateJob has got the writer lock \n");
fp_new = fopen("/etc/job_tmp.conf","w") ; while(fread((void *)job_ptr,sizeof(DownloadJob),1,fp)) { //jprintf("in UpdateJob() , %s \n",job_ptr->fullpath_name);
if(!strcmp(job_ptr->fullpath_name,job->fullpath_name)) { // jprintf("job_ptr->fullpath_name = %s , job->fullpath_name = %s\n",job_ptr->fullpath_name,job->fullpath_name);
if(flag == JOB_DEL) continue; else { // jprintf("job_ptr size = %u\n",sizeof(*job_ptr));
// jprintf("job size = %u\n",sizeof(*job));
// jprintf("job->SambaFullPathName = %s\n",job->SambaFullPathName);
*job_ptr = *job; //job_ptr = job;
isFound = 1; } } // jprintf("job_ptr->SambaFullPathName = %s\n",job_ptr->SambaFullPathName);
fwrite((void *)job_ptr,sizeof(DownloadJob),1,fp_new); } if(!isFound) //this record is new , I append it at the end of file
{ if(flag != JOB_DEL) fwrite((void *)job,sizeof(DownloadJob),1,fp_new); } //lockf(fd,F_ULOCK,0);
fflush(fp_new); fclose(fp_new); sync(); snprintf(buf,sizeof(buf)-1,"cp -f /etc/job_tmp.conf %s",JOB_CONF); system(buf); unlink("/etc/job_tmp.conf"); un_lock(fd,0,SEEK_SET,0); fclose(fp); } sync(); return 0; }
|
|
|