我正在为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
手动创建文件时,我确实收到了创建和修改事件。
这种行为有原因吗?我是以错误的方式接近这个吗?
答案 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;
}