linux文件锁

文件锁,控制颗粒度可以到文件的一行记录,方便数据库使用。文件锁用于进程间同步。

 

开发环境:cetos6.3(64),eclipse helios +cdt.

首先,定义一个文件锁类。

CFileLockHandler.h:

/*
 * CFileLockHandler.h
 *
 *  Created on: 2014-9-28
 *      Author: root
 */

#ifndef CFILELOCKHANDLER_H_
#define CFILELOCKHANDLER_H_

#include <fcntl.h>

class CFileLockHandler
{

public:
    CFileLockHandler();
    ~CFileLockHandler();

    int  InitialFileLock(const char* pchLockFile);


    void MutexOnFileRead(off_t iBeginIndex, off_t iLen);
    void MutexOnFileWrite(off_t iBeginIndex, off_t iLen);
    void FileMutexOff(off_t iBeginIndex, off_t iLen);
    char* GetErrMsg() { return m_szErrMsg;}

private:

    char m_szLockFileName[256];
    int m_iFileLockFd;
    struct flock m_stFLock;

    char m_szErrMsg[512];


    void CleanupFileLock();

};

#endif /* CFILELOCKHANDLER_H_ */

 

CFileLockHandler.cpp:

/*
 * CFileLockHandler.cpp
 *
 *  Created on: 2014-9-28
 *      Author: root
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>

#include "CFileLockHandler.h"

CFileLockHandler::CFileLockHandler()
{
    memset(m_szLockFileName, 0x0, sizeof(m_szLockFileName));
    memset(m_szErrMsg, 0x0, sizeof(m_szErrMsg));
    m_iFileLockFd = -1;
}

CFileLockHandler::~CFileLockHandler()
{
    //CleanupFileLock();
}

int CFileLockHandler::InitialFileLock(const char* pchLockFile)
{
    strncpy(m_szLockFileName, pchLockFile, sizeof(m_szLockFileName)-1);

    m_iFileLockFd = open(m_szLockFileName, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    if(m_iFileLockFd < 0)
    {
        snprintf(m_szErrMsg, sizeof(m_szErrMsg), "open lock file:%s fail:%s",
                    m_szLockFileName, strerror(errno));
        return -1;
    }

    return 0;
}

void CFileLockHandler::CleanupFileLock()
{
    if(m_iFileLockFd > 0)
        close(m_iFileLockFd);
}

void CFileLockHandler::MutexOnFileRead(off_t iBeginIndex, off_t iLen)
{
    //DEBUG_LOG( "MutexOnFileRead" );

    m_stFLock.l_type   = F_RDLCK;
    m_stFLock.l_start  = iBeginIndex;
    m_stFLock.l_whence = SEEK_SET;
    m_stFLock.l_len = iLen;

    int iTryTimes = 0;
    int iRet = 0;
    //fprintf(stderr, "waitting rlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
    //如果文件锁被请他进程占有,很多时候代码执行到这里,函数会阻塞。直到获取到文件锁,当然函数也有出现错误而立刻返回的情况。
    while ((iRet = fcntl(m_iFileLockFd, F_SETLKW, &m_stFLock)) < 0)
    {
        fprintf(stderr, "xxxxxxxxxxxxxxxxxxx:%lld, %lld\n", (long long)getpid(), (long long)errno);

        //positive keep locking
        if(EAGAIN == errno || EACCES == errno || EINTR == errno)
            continue;
        else if(EBADF == errno || EINVAL == errno || EOVERFLOW == errno || EDEADLK == errno)
        {
            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileRead dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);

            printf("CFileLockHandler::MutexOnFileRead dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            exit(-1);
        }
        //other error
        else
        {
            if(5 >= ++iTryTimes)
                continue;

            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileRead unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            printf("CFileLockHandler::MutexOnFileRead unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            break;
        }

        /*if(errno != EINTR)
        {
            //ERROR_LOG( "MutexOnFileRead fcntl failed.err[%s]", strerror(errno) );
            return;
        }*/
    }

    //fprintf(stderr, "in rlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
}

void CFileLockHandler::MutexOnFileWrite(off_t iBeginIndex, off_t iLen)
{
    //DEBUG_LOG( "MutexOnFileWrite" );
    m_stFLock.l_type = F_WRLCK;
    m_stFLock.l_start = iBeginIndex;
    m_stFLock.l_whence = SEEK_SET;
    m_stFLock.l_len = iLen;

    int iTryTimes = 0;
    int iRet = 0;
    //fprintf(stderr, "waitting wlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
    //如果文件锁被请他进程占有,很多时候代码执行到这里,函数会阻塞。直到获取到文件锁,当然函数也有出现错误而立刻返回的情况。
    while ((iRet = fcntl(m_iFileLockFd, F_SETLKW, &m_stFLock)) < 0)
    {
        fprintf(stderr, "xxxxxxxxxxxxxxxxxxx:%lld, %lld\n", (long long)getpid(), (long long)errno);

        //positive keep locking
        if(EAGAIN == errno || EACCES == errno || EINTR == errno)
            continue;
        else if(EBADF == errno || EINVAL == errno || EOVERFLOW == errno || EDEADLK == errno)
        {
            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileWrite dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);

            printf("CFileLockHandler::MutexOnFileWrite dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            exit(-1);
        }
        //other error
        else
        {
            if(5 >= ++iTryTimes)
                continue;

            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileWrite unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            printf("CFileLockHandler::MutexOnFileWrite unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            break;
        }

        /*if(errno != EINTR)
        {
            //ERROR_LOG( "MutexOnFileWrite fcntl failed.err[%s]", strerror(errno) );
            return;
        }*/
    }

    //fprintf(stderr, "in wlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
}


void CFileLockHandler::FileMutexOff(off_t iBeginIndex, off_t iLen)
{
    //DEBUG_LOG( "FileMutexOff" );
    m_stFLock.l_type = F_UNLCK;
    m_stFLock.l_start = iBeginIndex;
    m_stFLock.l_whence = SEEK_SET;
    m_stFLock.l_len = iLen;

    int iTryTimes = 0;
    int iRet = 0;

    //fprintf(stderr, "before unlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
    while ((iRet = fcntl(m_iFileLockFd, F_SETLKW, &m_stFLock)) < 0)
    {
        fprintf(stderr, "xxxxxxxxxxxxxxxxxxx:%lld, %lld\n", (long long)getpid(), (long long)errno);

        if(EAGAIN == errno || EACCES == errno || EINTR == errno)
            continue;
        else if(EBADF == errno || EINVAL == errno || EOVERFLOW == errno || EDEADLK == errno)
        {
            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileWrite dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);

            printf("CFileLockHandler::MutexOnFileWrite dead error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            exit(-1);
        }
        //other error
        else
        {
            if(5 >= ++iTryTimes)
                continue;

            openlog("tuan_server", LOG_CONS|LOG_PID, LOG_DAEMON);
            syslog(LOG_ERR, "CFileLockHandler::MutexOnFileWrite unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);

            printf("CFileLockHandler::MutexOnFileWrite unhandled error, iRet=%d, errno:%d, iBeginIndex:%zd", iRet, errno, iBeginIndex);
            break;
        }

        /*if(errno != EINTR)
        {
            //ERROR_LOG( "FileMutexOff fcntl failed.err[%s]", strerror(errno) );
            return;
        }*/
    }
    //fprintf(stderr, "after unlock:%lld, %lld, %lld, %d\n", (long long)getpid(), (long long)iBeginIndex, (long long)errno, iRet);
}

 

主程序test.cpp:

//============================================================================
// Name        : test.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include "CFileLockHandler.h"
#include <stdio.h>
#include <iostream>
using namespace std;

int main() {
    int iRet;
    CFileLockHandler pcLockHandler;

    pid_t pid = fork();
    if( pid < 0 )
    {
        //出错
        fprintf( stderr, "fork failed.\n" );
        return 1;
    }
    else if( pid > 0 )
    {
        //父进程
        iRet=pcLockHandler.InitialFileLock("/tmp/test.lock");
        if(0!=iRet)
        {
            printf("InitialFileLock fail.\n");
            return -1;
        }
        pcLockHandler.MutexOnFileWrite(0,1);
        printf("get write-lock first\n");
        pcLockHandler.MutexOnFileWrite(0,1);
        printf("get write-lock second\n");
        cout << "!!!Hello World!!!" << endl;
    }
    else
    {
        //子进程
        iRet=pcLockHandler.InitialFileLock("/tmp/test.lock");
        if(0!=iRet)
        {
            printf("子进程InitialFileLock fail.\n");
            return -1;
        }
        pcLockHandler.MutexOnFileWrite(0,1);
        printf("子进程get write-lock first\n");
        pcLockHandler.MutexOnFileWrite(0,1);
        printf("子进程get write-lock second\n");
        cout << "子进程!!!Hello World!!!" << endl;
    }

    printf("pls enter any key...\n");
    getchar();
    return 0;
}

 

运行效果如下,首先父进程两次都能获取到文件锁写。按回车键后,父进程释放文件锁写。子进程接着获取到文件锁写。

有用的命令:pkill,此命令用来删除所有调试时运行而忘记关闭的进程。

pkill -9 test

 

完。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。