2016-11-15 20 views
1

Я пишу тесты для библиотеки inotify, и сейчас я работаю над захватом события IN_CREATE. Я пытаюсь использовать boost :: filesystem :: ofstream, который по существу является std :: basic_ofstream, но я не получаю событие IN_CREATE.Почему поток не запускается IN_CREATE

Есть два потока в исполнении, основной поток, и один я создаю, который обрабатывает события, как так:

std::thread thread([&]() 
{ 
    boost::asio::io_service::work(g_io_service); 
    g_io_service.run(); 
} 

Всякий раз, когда событие принимается, библиотека вызывает эту функцию в контексте указанной выше теме :

[&](event_type event, std::string const & path) 
{ 
    std::lock_guard<std::mutex> lock(ready_mtx); 
    events.push_back(event); 
    condition.notify_all(); 
    ready = true; 
} 

Что тест выглядит (основной поток):

{ 
    boost::filesystem::ofstream file(path); 
    file << "test"; 
} 
{ 
    std::lock_guard<std::mutex> lock(ready_mtx); 
    while (!ready) 
     condition.wait(lock); 
    REQUIRE(events[0] == event_type::FILE_CREATE); 
} 

Я ожидаю событие для создания и изменения файла, и файл фактически создается, когда я ищу его в терминале, но я не получаю никакого события. Однако, когда я вручную создаю файл с echo "test" > test.file, я получаю создание и изменение событий.

Есть ли причина для такого поведения? Я подхожу к этому неправильно?

+0

Вы видите событие, когда вы закрываете поток? – Barmar

+0

Нет, деструктор вызовов из потока близок. – pierobot

+0

Я не могу придумать ни одного, что применимо в этом случае, но посмотрите в разделе «Предостережения» документации 'inotify': http://man7.org/linux/man-pages/man7/inotify.7.html – Barmar

ответ

1

Я создал следующее без моей библиотеки, и все работает отлично. Я, очевидно, что-то неправильно сделал в своем коде. Благодарю.

#include <atomic> 
#include <condition_variable> 
#include <fstream> 
#include <functional> 
#include <iostream> 
#include <iterator> 
#include <string> 
#include <thread> 

#include <linux/limits.h> 
#include <sys/inotify.h> 
#include <unistd.h> 

std::mutex cout_mtx; 
std::string path("/tmp/test-inotify"); 
std::string filename("test.file"); 

void print(std::string const & msg) 
{ 
    std::lock_guard<std::mutex> lock(cout_mtx); 
    std::cout << msg << std::endl; 
} 

void thread_fn(int fd, std::function<void(int, std::string const & name)> callback) 
{ 
    std::string buffer; 
    buffer.resize(64 * (sizeof(inotify_event) + NAME_MAX + 1)); 

    while (true) 
    { 
     int bytes_read = ::read(fd, &buffer[0], buffer.size()); 
     if (bytes_read == -1) 
     { 
      if (errno != EAGAIN) 
      { 
       print("Fatal error to call read"); 
       break; 
      } 

     } 

     int offset = 0; 
     inotify_event const * event = nullptr; 
     for (; offset < bytes_read; offset += sizeof(inotify_event) + event->len) 
     { 
      event = reinterpret_cast<inotify_event const*>(&buffer[offset]); 
      if (event->mask & IN_IGNORED) 
      { 
       // rewatch 
       int wd = ::inotify_add_watch(fd, path.c_str(), IN_CREATE); 
       if (wd == -1) 
       { 
        print("Unable to rewatch directory"); 
        break; 
       } 
      } 

      std::string name; 
      std::copy(&event->name[0], &event->name[event->len], std::back_inserter(name)); 

      int event_value = event->mask & 0xffff; 
      callback(event_value, name); 
     } 
    } 
} 

int main() 
{ 
    int fd = ::inotify_init1(IN_NONBLOCK); 
    if (fd == -1) 
    { 
     print("inotifiy_init1 failed"); 
     return errno; 
    } 

    int wd = ::inotify_add_watch(fd, path.c_str(), IN_CREATE); 
    if (wd == -1) 
    { 
     print("inotify_add_watch failed"); 
     return errno; 
    } 

    std::atomic<bool> ready; 
    std::mutex ready_mtx; 
    std::condition_variable condition; 
    int first_event = -1; 
    std::thread thread([&]() 
    { 
     thread_fn(fd, 
      [&](int event, std::string const & name) 
     { 
      std::unique_lock<std::mutex> lock(ready_mtx); 
      print(std::to_string(event)); 

      if (event == IN_CREATE) 
      { 
       first_event = event; 
       print(name + " was created"); 
      } 

      condition.notify_all(); 
      ready = true; 
     }); 
    }); 

    { 
     std::ofstream file(path + "/" + filename); 
    } 
    { 
     std::unique_lock<std::mutex> lock(ready_mtx); 

     while (!ready) 
      condition.wait(lock); 

     if (first_event == IN_CREATE) 
      print("success"); 
     else 
      print("failure"); 
    } 

    thread.join(); 

    return 0; 
}