为什么ofstream不触发IN_CREATE

Why does ofstream not trigger IN_CREATE

我正在为一个 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 手动创建文件时,我确实收到了创建和修改事件。

这种行为有原因吗?我是不是用错了方法?

我在没有我的库的情况下创建了以下内容,它工作得很好。我显然在我自己的代码中做错了什么。谢谢

#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;
}