如何有效地使用boost::progress_display回调
How can I effectively use callbacks with boost::progress_display?
我想使用boost::progress_display回调。首先,我有一个类Foo,我需要从广播事件:
class Foo
{
public:
template <typename L>
void attachListener(L const &listener)
{
m_callback.connect(listener);
}
void doWork()
{
for(...stuff...) {
m_callback(m_someData);
}
}
private:
Data m_someData;
boost::signals2::signal<void(Data const&)> m_callback;
}
然后,在其他代码中,我有一个回调,用于处理来自Foo的事件。然后,我在otherFunction中创建一个Foo,并为它附加回调:
void callback(Data const &someData, boost::progress_display &pd)
{
// other stuff
++pd;
}
void otherFunction()
{
boost::progress_display pd(100);
boost::function<void(Data const&)> f(boost::bind(&callback, _1, boost::ref(pd)));
Foo foo;
foo.attachListener(f);
foo.doWork();
}
当上面运行时,回调将从Foo::doWork调用。
这是正确的方式来使用回调与boost::progress_display结合?
当我需要创建和附加多个处理程序时,每个处理程序都有自己的boost::progress_display,这会变得很烦人。这样做将意味着每个单独的progress_display百分比条被一个接一个地打印出来。
谢谢,本。
UPDATE作为对评论的回应,这里有一个简单的progress_group
和group_progress_display
类的实现,它们一起可以很容易地显示几个不同的进度项(progress_group::item
实例)的单个进度条。
查看Live On Coliru。
让我们看看progress_group
:
struct progress_group {
struct item {
size_t current, total;
item(size_t total=100, size_t current=0)
: current(current), total(total) { }
void tick() {
if (current < total) current++;
}
};
std::list<boost::weak_ptr<progress_group::item> > members;
void add(boost::shared_ptr<item> const& pi) {
assert(pi);
members.push_back(pi);
}
item get_cumulative() {
item cumul(0, 0);
for(auto& wpi : members) {
auto pi = wpi.lock();
if (pi) {
cumul.current += pi->current;
cumul.total += pi->total;
}
}
return cumul;
}
};
请注意,我(任意)选择使用弱指针,这样进度项可能会消失,比例将被调整。
实际的进度是动态地缩放到底层显示部件(boost::progress_display
)的分辨率。这留下的主要限制是进度需要严格地随时间增加(因为输出可能不是到tty):
struct group_progress_display {
group_progress_display() : _display(1000), _reentrancy(0) {
}
void add(boost::shared_ptr<progress_group::item> pi) {
_group.add(pi);
}
void update() {
if (1 == ++_reentrancy) // cheap synch
{
auto cumul = _group.get_cumulative();
if (cumul.total > 0)
{
size_t target = (1.0 * cumul.current)/cumul.total * _display.expected_count();
if (target >= _display.count())
_display += target - _display.count();
}
}
--_reentrancy;
}
private:
boost::progress_display _display;
progress_group _group;
boost::atomic_int _reentrancy;
};
这个示例在线程中运行100个不同负载的后台作业,并显示单个累积进度小部件:
int main()
{
boost::thread_group workers;
group_progress_display display;
for (int i = 0; i < 100; ++i)
{
auto load = (rand()%5) * 1500;
auto progress_item = boost::make_shared<progress_group::item>(load);
display.add(progress_item);
worker this_worker(progress_item->total);
this_worker.attachListener([=,&display]{
progress_item->tick();
display.update();
});
workers.create_thread(this_worker);
}
workers.join_all();
}
(注意lambda(或c++03的boost::bind
表达式)本身是如何保持共享指针活动的)
worker
对进度实现一无所知:
struct worker {
explicit worker(size_t count) : count(count) {}
template <typename L>
void attachListener(L&& listener) {
m_callback = std::forward<L>(listener);
}
void operator()()
{
for (size_t i = 0; i < count; ++i) {
boost::this_thread::sleep_for(boost::chrono::microseconds(500));
m_callback();
}
}
private:
boost::function<void()> m_callback;
size_t count;
};
老回答
Live On Coliru
一个潜在的问题是,在这个时刻,进度指示器在某种程度上必须有关于过程步骤的准确信息。您可能希望隐藏该信息(在Data中,或将其包装在一个类中,该类也添加了进度信息),然后使用一些简单的算术可以将其转换为固定的比例(例如100)。
这将允许你的Foo::doWork
动态调整比例,这几乎证明了解耦是有效的。
- C++ Xcode 9 - 无法从 Cimg 调用函数 display()
- window.display() 单独在显示的最后一个缓冲区和当前缓冲区之间切换
- 需要有关在 C++ 中的函数 display() 上查找未定义引用的帮助
- 使用 WinApi 获取与面板中相同的显示名称"Advanced display settings"
- RenderWindow.display()导致SFML崩溃
- opencv: namedWindow() 错误"can't open display"!
- 排序时如何找出"progress"?
- 我需要创建一个Display()方法,它将显示所有属性
- C++BST-不使用递归调用display()函数
- cimg display()什么都没有,但调试消息是正确的
- 如何使用以集合为参数的模板化客户端display()函数
- C ++ SFML 数组[5] for loop window.display中的字符串,仅显示第1,3,5行
- QDesktopWidget for an X display
- 我的'show progress thread'在计数时无法运行
- Eclipse CDT Kepler 不允许"Display as array..."
- CUDA 内核导致"display driver not responding",增加了 4 行
- 实际函数调用计数与 EXPECT_CALL(*mock, display()) 不匹配
- 如果没有X11的$DISPLAY,则无法自动启动bus-daemon
- QT .UI To Display .GIF?
- 对于X11中的每个窗口,Display都是唯一的