gpt4 book ai didi

c++ - 快速路径数据包处理的配置更新

转载 作者:行者123 更新时间:2023-11-30 05:22:10 25 4
gpt4 key购买 nike

我们有一个使用线程池处理传入数据包的应用程序。每个线程都有一个在数据包处理时使用的配置。

我们目前使用互斥锁在检查配置是否更改之前进行锁定。

这使得线程花费太多时间来锁定互斥量以检查是否有配置更新。我们想知道你们是否可以建议更快的替代方案。使用 C++ 实现

问候。

最佳答案

解决此问题的一种可能方法是通过 atomics via std::atomic .以下是您问题的简化版本的简化解决方案。在下文中,您的问题已简化为单处理器线程(原则上多个情况相同)。该解决方案的第一个版本在配置更改时“泄漏”。对于足够少的配置更改(至少根据我的经验,这是一种非常常见的情况),这可能是可以接受的。否则,我将在最后描述两种解决方法。

假设您从以下配置类开始:

#include <thread>
#include <vector>
#include <list>
#include <iostream>
#include <atomic>
#include <chrono>

constexpr int init_config_val = 3;

struct config{
int m_val = init_config_val;
};

配置有一个值字段,m_val .

现在让我们为指向配置的原子指针和配置列表设置类型:

using config_atomic_ptr_t = std::atomic<config *>;
using config_list_t = std::list<config>;

线程进程接受一个指向原子配置指针的指针。当它需要访问配置时,它会调用 std::atomic::load .

void process(config_atomic_ptr_t *conf) {
while(true) {
const config *current_config = conf->load();
...
}
}

(请注意,上面显示了线程在每次迭代时检查配置;在某些类型的应用程序中,“足够频繁”地检查它可能就足够了。)

当一个不同的线程想要设置配置时,它会调用下面的函数:

void modify_config(config_list_t &configs, config_atomic_ptr_t &current_config, config conf) {
configs.push_back(conf);
current_config.store(&*configs.rbegin());
}

该函数采用对配置列表的引用、对原子配置指针的引用以及一个新的配置对象。它将配置对象推到列表的末尾,然后使用 std::atomic::store 将指针设置为列表中的末尾元素。

这就是main可以设置东西:

int main() {
config_list_t configs;
configs.push_back(config{});
config_atomic_ptr_t current_config{&*configs.rbegin()};

std::thread processor(process, &current_config);
config new_conf{init_config_val + 1};
modify_config(configs, current_config, new_conf);
processor.join();
}

如前所述,每个配置更改都会将一个新的配置对象推送到列表中,因此该程序实际上具有无限的内存需求。

至少根据我的经验,原则上许多应用程序需要支持配置更改,但预计这种情况很少见。如果是这样,上述解决方案可能是可以接受的。 (事实上​​ ,您可以通过删除列表并仅在堆上分配新配置来简化事情。)

如果不是,至少有两种选择。

第一种选择涉及修复上述问题,如下所示:

  • config ,添加另一个描述配置版本的字段 - 例如,一个整数。
  • 发送process thread 也是指向 std::atomic<int> 的指针.
  • 周期性地(比如每 1000 次迭代一次),线程将检查它正在使用的配置的版本,并设置 std::atomic<int>反射(reflect)出来。
  • 清理线程(可能是主线程)也会定期检查 std::atomic<int> 的值,并相应地清理列表。

第二种方法是将一个指针传递给你的线程函数,指向类似 boost::lockfree::queue 的指针。 .在每次迭代(或每迭代次数一次)中,线程可以检查队列中的新配置,然后使用它。


完整示例

#include <thread>
#include <vector>
#include <list>
#include <iostream>
#include <atomic>
#include <chrono>

constexpr int init_config_val = 3;

struct config{
int m_val = init_config_val;
};

using config_atomic_ptr_t = std::atomic<config *>;
using config_list_t = std::list<config>;

void process(config_atomic_ptr_t *conf) {
while(true) {
const config *current_config = conf->load();
if(current_config->m_val != init_config_val)
break;
}
}

void modify_config(config_list_t &configs, config_atomic_ptr_t &current_config, config conf) {
configs.push_back(conf);
current_config.store(&*configs.rbegin());
}

int main() {
using namespace std::chrono_literals;

config_list_t configs;
configs.push_back(config{});
config_atomic_ptr_t current_config{&*configs.rbegin()};

std::thread processor(process, &current_config);
std::this_thread::sleep_for(1s);
config new_conf{init_config_val + 1};
modify_config(configs, current_config, new_conf);
processor.join();
}

关于c++ - 快速路径数据包处理的配置更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39787473/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com