为什么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;
}
我正在为一个 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;
}