如何在linux下创建一个带超时的文件Lock

时间:2017-02-15 22:08:21

标签: c linux multithreading

我试图锁定linux下多个应用程序访问的一些关键资源。

所有应用程序将在进入临界区时调用相同文件上的acquireLock函数,并在离开时调用releaseLock。 如果锁定时间不超过时间,则呼叫者将继续执行其他操作。

下面的代码可用于慢速进程,但在压力下锁很容易被破坏锁被多个进程获取,所以我想我在某个地方遇到了竞争条件。 / p>

有人可以指出为什么它不起作用以及正确的实施方式会是什么?

非常感谢!

MV

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>

//************************************************************
#define CYCLETIME 1000
//************************************************************

//************************************************************
int acquireLock(char *lockFile, int msTimeout) 
{

    int lockFd;
    int cntTimeout = 0;

    if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO))  < 0)
        return -1;

    while (flock(lockFd, LOCK_EX | LOCK_NB) < 0){
        usleep(CYCLETIME);
        cntTimeout++;
    if(cntTimeout >= msTimeout){
        return -1;
        }
    }

    return lockFd;
}
//*************************************************************
void releaseLock (int lockFd) 
{
    flock(lockFd, LOCK_UN);
    close(lockFd);
}
//************************************************************

1 个答案:

答案 0 :(得分:1)

似乎错误出现在代码的另一部分,锁定正在按预期工作。

我分享了我用过的代码,以防它对其他人有帮助。

这些是锁定功能:

/* ----------------------------------------------------------------------- *
 *  Code derived by the flock.c in the "util-linux" ubuntu package 
 *  by  Peter Anvin 
 * ----------------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>

//************************************************************
static sig_atomic_t timeout_expired = 0;
//************************************************************

static void timeout_handler(int sig)
{
  (void)sig;

  timeout_expired = 1;
}


//************************************************************
int acquireLock(char *lockFile, int msTimeout) 
{
    struct itimerval timeout, old_timer;
    struct sigaction sa, old_sa;
    int err;
    int sTimeout = msTimeout/1000;
    memset(&timeout, 0, sizeof timeout);

    timeout.it_value.tv_sec = sTimeout;
    timeout.it_value.tv_usec = ((msTimeout-(sTimeout*1000))*1000);

    memset(&sa, 0, sizeof sa);

    sa.sa_handler = timeout_handler;
    sa.sa_flags   = SA_RESETHAND;
    sigaction(SIGALRM, &sa, &old_sa);
    setitimer(ITIMER_REAL, &timeout, &old_timer);


    int lockFd;
    int cntTimeout = 0;

    if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO))  < 0)
        return -1;

    while (flock(lockFd, LOCK_EX))
    {
        switch( (err = errno) ) {
            case EINTR:         /* Signal received */
                if ( timeout_expired )
                    setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
                    sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
                    return -1;      /* -w option set and failed to lock */
                continue;           /* otherwise try again */
            default:            /* Other errors */
                return -1;  
        }
    }   

    setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
    sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */

    return lockFd;
}
//***************************************************************
void releaseLock (int lockFd) 
{
    flock(lockFd, LOCK_UN);
    close(lockFd);
}
//************************************************************

......那些可以通过读写FIFO来尝试

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "lock.h"

#define LOCKED 1

void main(int argc, char **argv)

{
    const char *filename;
    const char *fifo_name;
    const char *message;
    int lockfd, fifoHandle;
    filename = argv[1];
    fifo_name = argv[2];
    message = argv[3];
    char bufin[1024];
    char bufout[1024];
    struct stat st;
    int bufsize = strlen(message)+1;
    int sleeptime = 0;
    int j = 0;

    if (stat(fifo_name, &st) != 0)
        mkfifo(fifo_name, 0666);

    while (1){

    if (LOCKED)
        lockfd=acquireLock(filename, 15000);

    if (lockfd==-1)
        printf("timeout expired \n");

    fifoHandle= open(fifo_name, O_RDWR);
    strcpy(bufin, message);
    bufin[bufsize-1] = 0x0;
    write(fifoHandle, bufin, sizeof(char)*bufsize);
    sleeptime = rand() % 100000;
    usleep(sleeptime);
    read(fifoHandle, &bufout, sizeof(char)*(bufsize+1));
    printf("%s - %d \n", bufout, j);
    j= j+1;
    if (LOCKED)
        releaseLock(lockfd);

    sleeptime = rand() % 10000;

    }

    unlink(fifo_name);


    return;

}

通过发送两个终端

./ locktestFIFO ./lck ./fifo messageA ./locktestFIFO ./lck ./fifo messageB

如果LOCKED未设置为1,则消息将混淆,否则两个线程将正确地获取和释放资源。