Inherits from Task
The ProgressMonitor
class is a specialized task that tracks and responds to progress events
across multiple tasks. It provides a central mechanism for monitoring task execution progress,
consolidating progress information, and generating notifications when significant milestones are
reached.
class ProgressMonitor : public Task {
public:
// Constructor
ProgressMonitor(float milestoneStep = 0.25f);
// Event handlers
void onProgress(const ArgumentPack& args);
void onTaskStarted();
void onTaskFinished();
void onTaskError(const ArgumentPack& args);
// Configuration
void setTaskCount(int count);
void setMilestoneStep(float step);
void resetProgress();
// Status methods
float getOverallProgress() const;
int getStartedTaskCount() const;
int getCompletedTaskCount() const;
int getFailedTaskCount() const;
bool isComplete() const;
// Milestone management
void addCustomMilestone(float milestone, const std::string& name);
void clearCustomMilestones();
};
ProgressMonitor emits the following signals:
Signal | Description | Arguments |
---|---|---|
progressUpdated |
When overall progress changes | overallProgress, completedTasks, totalTasks |
milestoneReached |
When a progress milestone is reached | milestoneName, milestoneValue, overallProgress |
allTasksComplete |
When all tasks have completed | totalTasks, successCount, failureCount, totalTimeMs |
summary |
When a progress summary is generated | taskCount, completedCount, failedCount, overallProgress |
// Create a progress monitor
auto progressMonitor = std::make_shared<ProgressMonitor>();
// Set the total number of tasks to monitor
progressMonitor->setTaskCount(5);
// Connect to milestone signals
progressMonitor->connectData("milestoneReached", [](const ArgumentPack& args) {
std::string milestoneName = args.get<std::string>(0);
float progress = args.get<float>(2);
std::cout << "Milestone reached: " << milestoneName
<< " (" << (progress * 100) << "%)" << std::endl;
});
// Connect to completion signal
progressMonitor->connectData("allTasksComplete", [](const ArgumentPack& args) {
int totalTasks = args.get<int>(0);
int successCount = args.get<int>(1);
int64_t totalTimeMs = args.get<int64_t>(3);
std::cout << "All tasks completed: " << successCount << "/" << totalTasks
<< " succeeded in " << totalTimeMs << "ms" << std::endl;
});
// Connect tasks to the monitor
for (auto& task : tasks) {
// Connect task signals to monitor handlers
task->connectSimple("started", progressMonitor.get(), &ProgressMonitor::onTaskStarted);
task->connectSimple("finished", progressMonitor.get(), &ProgressMonitor::onTaskFinished);
task->connectData("error", progressMonitor.get(), &ProgressMonitor::onTaskError);
task->connectData("progress", progressMonitor.get(), &ProgressMonitor::onProgress);
}
// Add custom milestones if needed
progressMonitor->addCustomMilestone(0.5f, "Halfway Point");
progressMonitor->addCustomMilestone(0.9f, "Almost Complete");
// Get current progress information
float currentProgress = progressMonitor->getOverallProgress();
int completedTasks = progressMonitor->getCompletedTaskCount();
// Create a thread pool and progress monitor
auto pool = std::make_shared<ThreadPool>();
auto monitor = std::make_shared<ProgressMonitor>();
// Add tasks to the pool
for (int i = 0; i < 10; i++) {
auto task = pool->createAndAdd<MyTask>("Task " + std::to_string(i), i * 100);
// Connect task signals to the monitor
task->connectSimple("started", monitor.get(), &ProgressMonitor::onTaskStarted);
task->connectSimple("finished", monitor.get(), &ProgressMonitor::onTaskFinished);
task->connectData("error", monitor.get(), &ProgressMonitor::onTaskError);
task->connectData("progress", monitor.get(), &ProgressMonitor::onProgress);
}
// Set the expected task count
monitor->setTaskCount(10);
// Connect to milestone signals for updates
monitor->connectData("milestoneReached", [](const ArgumentPack& args) {
std::string milestoneName = args.get<std::string>(0);
float progress = args.get<float>(2);
// Update UI with progress
updateProgressBar(progress);
showMilestoneNotification(milestoneName, progress);
});
// Connect to completion signal for final status
monitor->connectData("allTasksComplete", [](const ArgumentPack& args) {
int totalTasks = args.get<int>(0);
int successCount = args.get<int>(1);
int failureCount = args.get<int>(2);
int64_t totalTimeMs = args.get<int64_t>(3);
// Show completion dialog
showCompletionDialog(successCount, failureCount, totalTimeMs);
});
// Run all tasks
pool->exec();
// Create a progress monitor with custom milestone step
auto monitor = std::make_shared<ProgressMonitor>(0.1f); // 10% steps
// Add specific named milestones
monitor->addCustomMilestone(0.25f, "Quarter Complete");
monitor->addCustomMilestone(0.5f, "Halfway Point");
monitor->addCustomMilestone(0.75f, "Three-quarters Complete");
monitor->addCustomMilestone(0.95f, "Almost Finished");
monitor->addCustomMilestone(1.0f, "Complete");
// Connect milestone signal to UI updates
monitor->connectData("milestoneReached", [](const ArgumentPack& args) {
std::string milestoneName = args.get<std::string>(0);
float milestoneValue = args.get<float>(1);
// Update UI
updateProgressUI(milestoneValue, milestoneName);
// Log the milestone
std::cout << "Milestone: " << milestoneName << " at "
<< (milestoneValue * 100) << "%" << std::endl;
});
// Connect progress updates for continuous UI feedback
monitor->connectData("progressUpdated", [](const ArgumentPack& args) {
float progress = args.get<float>(0);
updateProgressBar(progress);
});
// Set up tasks with different weights
// Complex tasks will contribute more to overall progress
setTasksWithWeights(monitor);
The ProgressMonitor operates through the following mechanisms:
setTaskCount()
onProgress()
updates its trackingmilestoneReached
signal is emittedonTaskStarted()
tracks when tasks begin executiononTaskFinished()
records successful completionsonTaskError()
records failed tasksallTasksComplete
signal is emitted with summary informationvoid ProgressMonitor::onProgress(const ArgumentPack& args) {
// Extract progress value from args (typically 0.0 to 1.0)
float taskProgress = args.get<float>(0);
// Get task ID or use a default identifier
std::string taskId = "task_" + std::to_string(m_taskProgressMap.size());
if (args.size() > 1) {
taskId = args.get<std::string>(1);
}
// Update progress for this task
m_taskProgressMap[taskId] = taskProgress;
// Calculate aggregate progress
calculateOverallProgress();
// Check if we've crossed any milestones
checkMilestones();
}
ProgressMonitor supports multiple methods for calculating overall progress:
float ProgressMonitor::calculateAverageProgress() const {
if (m_taskProgressMap.empty()) {
return 0.0f;
}
float totalProgress = 0.0f;
// Sum all task progress values
for (const auto& [taskId, progress] : m_taskProgressMap) {
totalProgress += progress;
}
// Return average progress
return totalProgress / m_taskProgressMap.size();
}
float ProgressMonitor::calculateWeightedProgress() const {
if (m_taskWeights.empty()) {
// Fall back to average if no weights defined
return calculateAverageProgress();
}
float totalProgress = 0.0f;
float totalWeight = 0.0f;
// Sum weighted progress values
for (const auto& [taskId, progress] : m_taskProgressMap) {
float weight = m_taskWeights.count(taskId) ? m_taskWeights.at(taskId) : 1.0f;
totalProgress += progress * weight;
totalWeight += weight;
}
// Return weighted average
return totalWeight > 0.0f ? totalProgress / totalWeight : 0.0f;
}
float ProgressMonitor::calculateCompletionProgress() const {
// Count completed tasks (progress == 1.0)
int completedCount = 0;
for (const auto& [taskId, progress] : m_taskProgressMap) {
if (progress >= 0.99f) { // Allow for floating-point imprecision
completedCount++;
}
}
// Return proportion of completed tasks
return m_totalTaskCount > 0 ?
static_cast<float>(completedCount) / m_totalTaskCount : 0.0f;
}
ProgressMonitor is particularly useful for:
Tracking progress across multi-stage operations such as:
Providing accurate progress information to users during lengthy operations:
Monitoring and reporting on batch job progress:
Tracking data extraction, transformation, and loading progress:
Monitoring multi-step installation processes:
ProgressMonitor provides flexible milestone configuration:
By default, ProgressMonitor tracks these milestones:
Application-specific milestones can be added:
// Configure milestones for detailed tracking
void setupDetailedMilestones(std::shared_ptr<ProgressMonitor> monitor) {
// Clear default milestones
monitor->clearCustomMilestones();
// Add fine-grained milestones
monitor->addCustomMilestone(0.10f, "Initial Setup");
monitor->addCustomMilestone(0.20f, "Data Validation");
monitor->addCustomMilestone(0.30f, "Processing Started");
monitor->addCustomMilestone(0.40f, "Preliminary Results");
monitor->addCustomMilestone(0.50f, "Halfway Point");
monitor->addCustomMilestone(0.60f, "Secondary Processing");
monitor->addCustomMilestone(0.70f, "Optimization Phase");
monitor->addCustomMilestone(0.80f, "Final Calculations");
monitor->addCustomMilestone(0.90f, "Verification Stage");
monitor->addCustomMilestone(0.95f, "Finalizing Results");
monitor->addCustomMilestone(1.00f, "Complete");
}
The default milestone interval can be adjusted:
// Create monitor with 10% milestone steps
auto monitor = std::make_shared<ProgressMonitor>(0.1f);
// Or adjust after creation
monitor->setMilestoneStep(0.05f); // 5% steps (very fine-grained)
ProgressMonitor tracks the full lifecycle of tasks:
void ProgressMonitor::onTaskStarted() {
m_startedTaskCount++;
// Record start time if this is the first task
if (m_startedTaskCount == 1) {
m_startTime = std::chrono::steady_clock::now();
}
// Emit status update
ArgumentPack args;
args.add<int>(m_startedTaskCount);
args.add<int>(m_totalTaskCount);
emit("taskStarted", args);
}
void ProgressMonitor::onTaskFinished() {
m_completedTaskCount++;
// Check if all tasks are now complete
if (isComplete()) {
// Calculate total execution time
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
now - m_startTime).count();
// Emit completion signal with summary data
ArgumentPack args;
args.add<int>(m_totalTaskCount);
args.add<int>(m_completedTaskCount);
args.add<int>(m_failedTaskCount);
args.add<int64_t>(duration);
emit("allTasksComplete", args);
}
}
void ProgressMonitor::onTaskError(const ArgumentPack& args) {
m_failedTaskCount++;
// Extract error message if available
std::string errorMsg = "Unknown error";
if (!args.empty()) {
errorMsg = args.get<std::string>(0);
}
// Log the failure
ArgumentPack errorArgs;
errorArgs.add<std::string>(errorMsg);
errorArgs.add<int>(m_failedTaskCount);
emit("taskFailed", errorArgs);
// Check if all tasks are now complete (success + failure = total)
if (isComplete()) {
onTaskFinished(); // Reuse completion logic
}
}
ProgressMonitor is designed to be thread-safe:
resetProgress()
when starting a new batch
of tasks