doucan2102 2017-10-27 22:48
浏览 65
已采纳

Fcntl in go不起作用

I'm currently writing a http server, that has to run over all files inside a folder. One Request can write a file, where another Request can read the files at the same time, so i need to lock the file, that is open for writing. In the Routine, that will read the file, i just want to skip the file that is locked. To make this, i want to use locklibrarys like that from rubyist or nightlyone.

The problem is, i didnt get them to work, so i started to call the syscall.FcntlFlock() function myself and it didn't work like i had expected.
This program doesn't work in the Go Playground, cause the playground seems to run not on a unix-based system (syscall.FcntlFlock is undefined)

The code that didn't work:

func main() {
    time.Sleep(time.Second)

    file, err := os.Open("lockfiletest.lock")
    if err != nil {
        log.Printf("error opening file2: %s", err)
        return
    }
    defer file.Close()

    flockT := syscall.Flock_t{
        Type: syscall.F_WRLCK,
        Whence: io.SeekStart,
        Start: 0,
        Len: 0,
    }
    err = syscall.FcntlFlock(file.Fd(), syscall.F_SETLK, &flockT)
    if err != nil {
        log.Printf("error locking file2: %s", err)
        return
    }

    log.Println("lock2 accessed")

    time.Sleep(time.Second * 5)

    log.Println("func2 finished")

    time.Sleep(time.Second * 15)
}

the console output:

2017/10/28 00:18:12 error locking file2: bad file descriptor
Process finished with exit code 0

What am i doing wrong? Are the syscalls broken?
I also tried it in C and there it works fine.
I test this program in Go1.8.3 and Go1.9.1 on ubuntu16.04

PS: This program also have to run on windows, so only implementing a FcntlLock isn't enough.


I also thoght about using sync.RWMutex, so it is locked via a Mutex instead of a fileLock. That is not exactly what i want, cause i only want to skip the file that is locked and not wait until the mutex can be locked.
  • 写回答

2条回答 默认 最新

  • dpfw3607 2017-10-28 00:51
    关注

    If I create the file with touch lockfiletest.lock, that is with no file contents, your program fails with your error: error locking file2: bad file descriptor.

    $ rm -f lockfiletest.lock
    $ touch lockfiletest.lock
    $ go run lockfiletest.go
    2017/10/27 21:17:27 error locking file2: bad file descriptor
    

    I changed the file open to closely match TestFcntlFlock.

    $ uname -s
    Linux
    ~/go/src/syscall$ $ go test -v -run=TestFcntlFlock syscall_unix_test.go
    === RUN   TestFcntlFlock
    --- PASS: TestFcntlFlock (0.01s)
    PASS
    ok      syscall 0.008s
    ~/go/src/syscall$ 
    

    For example,

    package main
    
    import (
        "io"
        "log"
        "os"
        "syscall"
        "time"
    )
    
    func main() {
        time.Sleep(time.Second)
    
        name := "lockfiletest.lock"
        file, err := os.OpenFile(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0666)
        if err != nil {
            log.Printf("error opening file: %s", err)
            return
        }
        defer file.Close()
    
        flockT := syscall.Flock_t{
            Type:   syscall.F_WRLCK,
            Whence: io.SeekStart,
            Start:  0,
            Len:    0,
        }
        err = syscall.FcntlFlock(file.Fd(), syscall.F_SETLK, &flockT)
        if err != nil {
            log.Printf("error locking file: %s", err)
            return
        }
    
        log.Println("lock2 accessed")
    
        time.Sleep(time.Second * 5)
    
        log.Println("func2 finished")
    
        time.Sleep(time.Second * 15)
    }
    

    Output:

    $ rm -f lockfiletest.lock
    $ touch lockfiletest.lock
    $ go run lockfiletest.go
    2017/10/27 21:21:56 lock2 accessed
    2017/10/27 21:22:01 func2 finished
    $ rm -f lockfiletest.lock
    $ go run lockfiletest.go
    2017/10/27 21:22:25 lock2 accessed
    2017/10/27 21:22:30 func2 finished
    $ go run lockfiletest.go
    2017/10/27 21:25:40 lock2 accessed
    2017/10/27 21:25:45 func2 finished
    $ 
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?