Понимание выбора из каналов с и без goroutine - PullRequest
0 голосов
/ 28 апреля 2018

Привет сообщество stackoverflow, Я использую github.com / fsnotify / fsnotify для установки наблюдателей на файл в Go. Моя функция выглядит как

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
}

, который работает до сих пор, и я получаю выходные данные как

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

Однако, если я попытаюсь удалить закрытие, запущенное в программе, и запустить его как

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
}

программа никогда ничего не выводит. Я запустил его с strace и программа застряла на

[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}

и не получает от канала и продолжает ждать.

Я читал, что это может быть вызвано небуферизованным каналом. Таким образом, чтобы проверить это, я изменил библиотеку для использования буферизованного канала, и часть функции, которая генерирует новый наблюдатель, выглядит как

    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{}),
}

Но поведение такое же. Может кто-нибудь помочь мне понять, почему чтение с канала работало, когда оно было в goroutine, и не работало без goroutine?

Спасибо.

1 Ответ

0 голосов
/ 28 апреля 2018

Я не знаком с fsnotify, но похоже, что он ничего не будет отправлять по каналам, пока не будет вызван Watcher.Add() для просмотра файла, но Watcher.Add() появляется после select во второй версии. В этом случае select будет заблокирован навсегда, поскольку ничего не может быть сигнализировано, поскольку Watcher.Add() не был вызван. Отсюда и тупик.

...