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.
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
$
您必须以WRONLY或RDWR格式打开文件,您只能以只读方式打开该文件以将其锁定,这是行不通的-您将获得一个只读文件描述符。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.