dongya1875 2018-04-28 17:23
浏览 67
已采纳

了解使用和不使用goroutine的通道中的选择

Hello stackoverflow community, I am using github.com/fsnotify/fsnotify to set watchers to a file in Go. My function looks like

func SetWatcher(filename string) {
    fmt.Println("Setting watcher to file ", filename)
    Watcher, err = fsnotify.NewWatcher()
    if err != nil {
        fmt.Println("inotify errored. Other methods needs to be implemented.")
        panic(err)
    }
    if err != nil {
        log.Fatal(err)
    }

    done := make(chan bool)
    go func() {
        for {
            select {
            case event := <-Watcher.Events:
                if event.Op == fsnotify.Remove {
                    fmt.Println("File removed, needs to kill the process.")
                } else if event.Op == fsnotify.Rename {
                    fmt.Println("File renamed, need to restart seeking.")
                }

            case err := <-Watcher.Errors:
                log.Println("error:", err)
            }
        }
    }()

    err = Watcher.Add(filename)
    if err != nil {
        log.Fatal(err)
    }
    <-done
}

which works so far and I get outputs as

Setting watcher to file  /var/log/syslog
File renamed, need to restart seeking.

However, if I try to remove the closure running in the goroutine and run it as

func SetWatcher(filename string) {
    fmt.Println("Setting watcher to file ", filename)
    Watcher, err = fsnotify.NewWatcher()
    if err != nil {
        fmt.Println("inotify errored. Other methods needs to be implemented.")
        panic(err)
    }
    if err != nil {
        log.Fatal(err)
    }
    //defer Watcher.Close()

    //done := make(chan bool)
    //go func() {
    //  for {
            select {
            case event := <-Watcher.Events:
                if event.Op == fsnotify.Remove {
                    fmt.Println("File removed, needs to kill the process.")
                } else if event.Op == fsnotify.Rename {
                    fmt.Println("File renamed, need to restart seeking.")
                }

            case err := <-Watcher.Errors:
                log.Println("error:", err)
            }
        //}
    //}()

    err = Watcher.Add(filename)
    if err != nil {
        log.Fatal(err)
    }
    //<-done
}

the program never outputs anything. I ran it with strace and the program is seen stuck at

[pid  5773] pselect6(0, NULL, NULL, NULL, {tv_sec=0, tv_nsec=20000}, NULL <unfinished ...>
[pid  5772] epoll_wait(4, [], 128, 0)   = 0
[pid  5772] futex(0x598bf8, FUTEX_WAIT, 0, NULL <unfinished ...>
[pid  5773] <... pselect6 resumed> )    = 0 (Timeout)
[pid  5740] <... pselect6 resumed> )    = 0 (Timeout)
[pid  5773] futex(0x598578, FUTEX_WAIT, 0, {tv_sec=60, tv_nsec=0} 
<unfinished ...>
[pid  5740] futex(0xae1f58, FUTEX_WAIT, 0, {tv_sec=60, tv_nsec=0}

and not receiving from the channel and keeps on waiting.

I've read that this could be caused because of non-buffered channel. So to validate that, I modified the library to use a buffered channel and the part of the function that generates the new watcher looks like

    w := &Watcher{
    fd:       fd,
    poller:   poller,
    watches:  make(map[string]*watch),
    paths:    make(map[int]string),
    Events:   make(chan Event, 10), // Made it buffered here
    Errors:   make(chan error),
    done:     make(chan struct{}),
    doneResp: make(chan struct{}),
}

But the behavior is the same. Can someone please help me understand why the reading from channel worked when it was in a goroutine, and didn't work without a goroutine?

Thank you.

  • 写回答

1条回答 默认 最新

  • dpuwov1487 2018-04-28 17:36
    关注

    I am not familiar with fsnotify, but it looks like it won't send anything on the channels until Watcher.Add() is called to watch the file, but the Watcher.Add() occurs after the select in the second version. In this case select will block for ever as nothing can be signaled as Watcher.Add() has not been called. Hence there is deadlock.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题