【转】进程间通信实例5> 读写者锁的用法

来源:互联网 发布:软件腰带图片 编辑:程序博客网 时间:2024/05/23 23:14

本文转自:http://blogold.chinaunix.net/u/22617/showart_215469.html

 

当两个进程都要读写一个文件的时候, 需要用读写锁。
 
代码:
 



//具体的细节和原理可以参阅 《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;
        
}