如何将 lambda 函数转发到底层 std::thread 构造函数以便在单独的线程中执行它?

问题描述 投票:0回答:1

给定路径,文件观察器会定期检查其可用性(在创建/删除的情况下)或时间戳(在文件存在且其内容已被修改的情况下)。下面的代码(取自here)正在进行中,我正在对其进行调整以支持单个文件(原始代码支持多个文件,其中给定路径是一个目录)。

class FileWatcher {
public:
    std::string m_path;
    std::chrono::duration<int, std::milli> m_delay;
    std::unique_ptr<std::thread> m_watcher_thread;

    FileWatcher(std::string path, std::chrono::duration<int, std::milli> delay);

    void start(const std::function<void(std::string, FileStatus)>& action);
private:
    std::unordered_map<std::string, std::filesystem::file_time_type> m_paths;
    bool m_running = true;

    bool contains(const std::string& key);
};

FileWatcher::FileWatcher(std::string path, std::chrono::duration<int, std::milli> delay) : m_path{ path }, m_delay{ delay } {
    // std::this_thread::sleep_for(delay);
    auto const p = std::filesystem::path(m_path);
    if (std::filesystem::is_regular_file(p))
    {
        m_paths[p.string()] = std::filesystem::last_write_time(p);
    }
    else if (std::filesystem::is_directory(p))
    {
        for (auto const& file : std::filesystem::recursive_directory_iterator(m_path)) {
            m_paths[file.path().string()] = std::filesystem::last_write_time(file);
        }
    }
    else
    {
        throw std::exception("Given path to watch is expected to be a regular file or directory");
    }
}

bool FileWatcher::contains(const std::string& key)
{
    auto el = m_paths.find(key);
    return el != m_paths.end();
}

void FileWatcher::start(const std::function<void(std::string, FileStatus)>& action) {
    m_watcher_thread = std::unique_ptr<std::thread>(new std::thread(&action));
    while (m_running) {
       ... // WIP Check status of file and call action
    }
}

我按如下方式初始化我的观察者:

config_watcher = std::shared_ptr<FileWatcher>(new FileWatcher{ "./config.json" , std::chrono::milliseconds(5000) });

并通过调用启动它(

logger_spd
是使用文件接收器的spdlog记录器的
std::shared_ptr

config_watcher->start([](std::string path, FileStatus status) -> void {
    // Process only regular files, all other file types are ignored
    if (!std::filesystem::is_regular_file(std::filesystem::path(path)) && status != FileStatus::erased) {
        return;
    }
    switch (status) {
    case FileStatus::created:
    {
        std::lock_guard<std::mutex> guard(config_update_mutex);
        logger_spd->info("Configuration created");
        break;
    }
    case FileStatus::modified:
    {
        std::lock_guard<std::mutex> guard(config_update_mutex);
        logger_spd->info("Configuration modified");
        break;
    }
    case FileStatus::erased:
    {
        std::lock_guard<std::mutex> guard(config_update_mutex);
        logger_spd->info("Configuration deleted");
        break;
    }
    default:
        std::lock_guard<std::mutex> guard(config_update_mutex);
        logger_spd->error("Unknown file status");
    }

    std::this_thread::sleep_for(config_watcher->m_delay);
    }
);

初始代码是次优的,至少在我用作源的文章下面的评论中提到过,因为除其他问题外,

std::this_thread::sleep_for()
内部的
FileWatcher::start()
调用阻止了程序的其余部分除非在单独的线程中实例化。这就是为什么我尝试修改代码以使其更像典型的工作线程,这意味着我想将
action
函数(
FileWatcher::start()
的参数)传递给底层线程构造函数,然后管理类内的所有内容.

我在通过

FileWatcher::start()
函数将 lambda 转发到底层线程的构造函数时遇到了问题。

c++ multithreading lambda c++17
1个回答
0
投票

您不应该使用

action
启动线程,而是应该有一个不同的函数,其中包含循环并在循环内调用
action
并为线程使用该函数。

也许是这样的:

void FileWatcher::start(const std::function<void(std::string, FileStatus)>& action) {
    m_watcher_thread = std::thread([action]() {
        while (m_running) {
            // Wait until something happens...
            action(file, status);
        }
    });
}

请注意,我没有对线程对象使用指针,因为不需要。

“睡眠”也应该在循环内部,而不是在

action
函数中。

© www.soinside.com 2019 - 2024. All rights reserved.