为什么ofstream不会触发IN_CREATE

时间:2016-11-15 19:08:27

标签: c++ fstream inotify boost-filesystem

我正在为inotify库编写测试,我正在努力捕获IN_CREATE事件。我正在尝试使用boost :: filesystem :: ofstream,它本质上是std :: basic_ofstream,但我没有得到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手动创建文件时,我确实收到了创建和修改事件。

这种行为有原因吗?我是以错误的方式接近这个吗?

1 个答案:

答案 0 :(得分: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;
}