为何文件句柄被自动关闭了?

问题描述: 我想用flock来控制程序只被启动一次,将保存pid的文件用flock互斥了一下,并一直持有这个句柄不关闭。 但我现在这个句柄,在我没有显式关闭的情况下,被go运行时自动给关闭了,不知道为何??

var pidFd *os.File

func outputPid(pidPath string) {
  if len(pidPath) == 0 {
    return
  }

  os.Mkdir(pidPath, 0755)
  _, name := path.Split(os.Args[0])
  pidPath += "/" + name + ".pid"
  pidFd, err := os.OpenFile(pidPath, os.O_CREATE|os.O_WRONLY, 0644)
  if err != nil {
    log.Fatalf("Error - %s output pid %s [%s]", name, pidPath, err)
  }

  // Luanch only one instance.
  if err := syscall.Flock(int(pidFd.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
    log.Fatalf("Error - %s flock failed [%s]", name, err)
  }
  pidFd.Truncate(0)
  pidFd.Write([]byte(strconv.Itoa(os.Getpid())))
  **// pidFd 并没有关闭**
}

strace跟踪结果

rt_sigaction(SIGRT_32, {0x43bd10, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x43bd80}, NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0xc208030000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD) = 26411
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
mkdir("pid", 0755)                      = -1 EEXIST (File exists)
open("pid/cuid.pid", O_WRONLY|O_CREAT|O_CLOEXEC, 0644) = 3      **// 打开文件,句柄是3**
flock(3, LOCK_EX|LOCK_NB)               = 0
ftruncate(3, 0)                         = 0
getpid()                                = 26410
write(3, "26410", 5)                    = 5
mkdir("log", 0755)                      = -1 EEXIST (File exists)
open("log/log", O_WRONLY|O_CREAT|O_APPEND|O_CLOEXEC, 0644) = 4
open("/etc/localtime", O_RDONLY)        = 5
read(5, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\3\0\0\0\0"..., 4096) = 405
read(5, "", 4096)                       = 0
close(5)                                = 0
write(4, "2015/03/29 09:49:07.463357 -----"..., 69) = 69
futex(0x5b5160, FUTEX_WAKE, 1)          = 1           **// 这里应该是进入select{}**
futex(0x5b50e0, FUTEX_WAKE, 1)          = 1
futex(0x5b5160, FUTEX_WAKE, 1)          = 1
futex(0x5b50e0, FUTEX_WAKE, 1)          = 1
close(3)                                = 0          **// 在这里被关闭了!!**
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
.....

整个main函数

func main() {
  parseFlag()

  if showVersion {
    fmt.Printf("version %s\n", "1.0.0")
    os.Exit(0)
  }

  if toDaemon {
    daemon()
  }

  //
  outputPid("pid")                           **这里**

  go signalHandle()

  if toProfile {
    prof.StartProf()
  }

  if err := initSvc(); err != nil {
    fmt.Printf("Error - init [%s]\n", err.Error())
    os.Exit(1)
  }
  ilog.Log("-------------launch ok ------------------")

  select {}

  os.Exit(1)
}

共 2 个回复


testing

看看是不是被GC回收了

# 0

shaovie

我声明的是全局变量啊

# 1