For multithreading collaborative scenarios, design ageneral-purpose multithreading middleware that supports thread state management (initialization → startup → running → waiting → stopping), dependency awareness, ordered switching, and error handling. Below is the complete implementation plan.
The design goals of the middleware — High versatility: Adapt to various types of threads, reducing expansion costs
-
Versatility: Supports the integration and management of different functional threads (such as data acquisition, algorithm processing, device control).
-
State Awareness: Real-time monitoring of all thread states (uninitialized/ready/running/waiting/stopped/error).
-
Ordered Control: Supports switching thread states based on dependency relationships (e.g., thread B starts after thread A completes).
-
Safe Switching: Ensures that thread state transitions are valid (e.g., prevents uninitialized threads from starting).
-
Error Propagation: Automatically triggers global stop or downgrade handling when any thread encounters an exception.
Core Architecture Design
This middleware abstracts complex multithreading collaboration issues into standardized state management and dependency coordination processes throughstate machine constraints, dependency resolution, and signal-slot communication, ensuring thesafety and orderliness of thread execution in practical use cases, while reducing functional expansion and maintenance costs through generalized design.

1. Layered Architecture Diagram
Application Layer: Integrates specific functional threads (such as data acquisition, processing), managing states through middleware interfaces.
-
Core Layer: Implements core logic such as state management, dependency resolution, notification triggering, and exception handling.
-
Support Layer: Implements inter-thread communication and synchronization based on Qt’s native mechanisms (threads, signal-slot, synchronization primitives).
Core Module Implementation
1. Thread State Enumeration and State Machine
Defines the full lifecycle states of a thread and constrains valid transitions through a state machine.
// ThreadState.h#pragma once
// Thread state enumeration (full lifecycle)enum class ThreadState { Uninitialized, // Uninitialized (initial state) Ready, // Ready (initialization complete, waiting to start) Running, // Running (executing tasks) Waiting, // Waiting (dependent on other threads to complete) Stopped, // Stopped (actively or passively stopped) Error // Error (runtime exception)};
// State transition rules (valid transition paths)const QMap<ThreadState, QVector<ThreadState>> VALID_TRANSITIONS = { {ThreadState::Uninitialized, {ThreadState::Ready}}, // Initialization → Ready {ThreadState::Ready, {ThreadState::Running, ThreadState::Stopped}}, // Ready → Running/Stopped {ThreadState::Running, {ThreadState::Waiting, ThreadState::Stopped, ThreadState::Error}}, // Running → Waiting/Stopped/Error {ThreadState::Waiting, {ThreadState::Running, ThreadState::Stopped}}, // Waiting → Running/Stopped {ThreadState::Stopped, {ThreadState::Ready, ThreadState::Uninitialized}}, // Stopped → Ready/Uninitialized (reset) {ThreadState::Error, {ThreadState::Stopped}} // Error → Stopped (non-recoverable)};
2. Thread Descriptor (Functional Thread Metadata)
Encapsulates core information of the thread (name, type, dependencies, state, etc.), serving as the smallest unit managed by the middleware.
// ThreadDescriptor.h#pragma once#include <QString>#include <QList>#include <QVariantMap>#include "ThreadState.h"
// Functional thread metadata descriptorstruct ThreadDescriptor { QString name; // Unique thread name (identifier) QString type; // Thread type (e.g., "DataAcquisition", "Algorithm") QList<QString> dependencies; // Names of dependent threads (must start first) ThreadState state; // Current state QVariantMap parameters; // Thread parameters (e.g., sampling frequency, algorithm threshold) QObject* instance; // Pointer to thread instance (subclass of QThread)
// Constructor ThreadDescriptor(const QString& name, const QString& type, const QList<QString>& deps = {}, const QVariantMap& params = {}) : name(name), type(type), dependencies(deps), state(ThreadState::Uninitialized), parameters(params), instance(nullptr) {}};
3. Core Class of Thread Middleware (ThreadMiddleware)
Globally manages all threads, implementing state switching, dependency resolution, notification triggering, and other core logic.
// ThreadMiddleware.h#pragma once#include <QObject>#include <QMap>#include <QList>#include <QMutex>#include <QWaitCondition>#include "ThreadDescriptor.h"
class ThreadMiddleware : public QObject { Q_OBJECT
public: // Singleton pattern (global unique middleware instance) static ThreadMiddleware* instance() { static ThreadMiddleware middleware; return &middleware; }
// Disable copy/move ThreadMiddleware(const ThreadMiddleware&) = delete; ThreadMiddleware& operator=(const ThreadMiddleware&) = delete;
// Register functional thread (requires thread instance and descriptor) bool registerThread(QObject* threadInstance, const ThreadDescriptor& descriptor);
// Initialize all threads (in dependency order) bool initializeThreads();
// Start specified thread (trigger state switch: Ready→Running) bool startThread(const QString& threadName);
// Stop specified thread (trigger state switch: Running→Stopped) bool stopThread(const QString& threadName);
// Wait for specified thread to complete (block current thread until target state) bool waitForThread(const QString& threadName, ThreadState targetState, int timeoutMs = 5000);
// Query thread state (thread-safe) ThreadState getThreadState(const QString& threadName) const;
// Trigger thread state switch (internal use, externally triggered by signals) void notifyThreadStateChanged(const QString& threadName, ThreadState newState);
signals: // Thread state change notification (external subscription) void threadStateChanged(const QString& threadName, ThreadState newState); // Thread initialization complete notification void threadInitialized(const QString& threadName); // Thread error notification void threadErrorOccurred(const QString& threadName, const QString& errorMsg);
private: ThreadMiddleware() = default; // Private constructor for singleton
// Internal methods bool validateTransition(const QString& threadName, ThreadState newState) const; void updateThreadState(const QString& threadName, ThreadState newState); QList<QString> getDependentThreads(const QString& threadName) const; void processWaitingThreads(); // Process threads in waiting state (check if dependencies are met)
QMap<QString, ThreadDescriptor> m_threads; // Registered thread descriptors mutable QMutex m_mutex; // Protect shared data QWaitCondition m_waitCond; // Condition variable (wait for state change)};
4. Base Class for Functional Threads (BaseFunctionThread)
All functional threads must inherit from this class, implementing specific business logic while decoupling from the middleware.
// BaseFunctionThread.h#pragma once#include <QThread>#include <QObject>#include "ThreadMiddleware.h"
class BaseFunctionThread : public QThread { Q_OBJECT
public: explicit BaseFunctionThread(const QString& threadName, QObject* parent = nullptr) : QThread(parent), m_threadName(threadName) {}
// Initialize thread (override to implement resource loading) virtual bool initialize() { qInfo() << "Thread" << m_threadName << "initialized"; emit initialized(); // Notify middleware that initialization is complete return true; }
// Start thread task (override to implement core logic) virtual void startTask() { qInfo() << "Thread" << m_threadName << "started, beginning task execution..."; // Simulate task execution (replace with business logic) for (int i = 0; i < 5; ++i) { QThread::msleep(1000); // Simulate time-consuming operation qInfo() << "Thread" << m_threadName << "executing step" << i; } emit taskCompleted(); // Notify middleware that the task is complete }
// Stop thread task (override to implement resource release) virtual void stopTask() { qInfo() << "Thread" << m_threadName << "stopped, releasing resources..."; }
// Get thread name QString name() const { return m_threadName; }
signals: // Initialization complete signal (triggers middleware state switch) void initialized(); // Task complete signal (triggers middleware state switch) void taskCompleted(); // Error signal (triggers middleware exception handling) void errorOccurred(const QString& errorMsg);
protected: QString m_threadName; // Thread name (consistent with middleware descriptor)};
Key Function Implementations
1. Thread Registration and Initialization
Register threads through the middleware, initializing in dependency order to ensure dependent threads start first.
// ThreadMiddleware.cppbool ThreadMiddleware::registerThread(QObject* threadInstance, const ThreadDescriptor& descriptor) { QMutexLocker locker(&m_mutex); if (m_threads.contains(descriptor.name)) { qWarning() << "Thread" << descriptor.name << "already registered"; return false; }
// Bind thread instance and descriptor ThreadDescriptor& desc = m_threads[descriptor.name]; desc.instance = threadInstance; desc.parameters = descriptor.parameters; desc.dependencies = descriptor.dependencies; desc.state = ThreadState::Uninitialized; return true;}
bool ThreadMiddleware::initializeThreads() { QMutexLocker locker(&m_mutex); // Initialize in topological order (threads without dependencies first) QList<QString> initOrder; for (const auto& [name, desc] : m_threads) { if (desc.dependencies.isEmpty()) { initOrder.append(name); } }
// Recursively handle dependencies (example simplified, actual needs topological sorting) for (const QString& name : initOrder) { ThreadDescriptor& desc = m_threads[name]; if (desc.state != ThreadState::Uninitialized) continue; // Call thread initialization interface if (BaseFunctionThread* thread = qobject_cast<BaseFunctionThread*>(desc.instance)) { if (!thread->initialize()) { qCritical() << "Thread" << name << "initialization failed"; desc.state = ThreadState::Error; emit threadErrorOccurred(name, "initialization failed"); return false; } desc.state = ThreadState::Ready; emit threadStateChanged(name, ThreadState::Ready); emit threadInitialized(name); } } return true;}
2. Thread State Switching and Dependency Checking
Check legality before state switching, automatically entering waiting state if dependent threads are not completed.
// ThreadMiddleware.cppbool ThreadMiddleware::validateTransition(const QString& threadName, ThreadState newState) const { const ThreadDescriptor& desc = m_threads.value(threadName); if (!m_threads.contains(threadName)) { qWarning() << "Thread" << threadName << "not registered"; return false; }
// Check if state transition is valid if (!VALID_TRANSITIONS.value(desc.state).contains(newState)) { qWarning() << "Thread" << threadName << "invalid state transition:" << stateToString(desc.state) << "→" << stateToString(newState); return false; }
// Check if dependencies are met (if needed) if (newState == ThreadState::Running) { for (const QString& dep : desc.dependencies) { if (m_threads.value(dep).state != ThreadState::Stopped) { qWarning() << "Thread" << threadName << "dependent thread" << dep << "not stopped"; return false; } } }
return true;}
void ThreadMiddleware::updateThreadState(const QString& threadName, ThreadState newState) { QMutexLocker locker(&m_mutex); if (!validateTransition(threadName, newState)) return; ThreadDescriptor& desc = m_threads[threadName]; desc.state = newState; emit threadStateChanged(threadName, newState); // Trigger dependency thread check (e.g., wake up waiting threads when current thread completes) if (newState == ThreadState::Stopped) { processWaitingThreads(); }}
3. Thread Waiting and Synchronization
Implement thread waiting through condition variables until dependent threads complete or timeout.
// ThreadMiddleware.cppbool ThreadMiddleware::waitForThread(const QString& threadName, ThreadState targetState, int timeoutMs) { QMutexLocker locker(&m_mutex); const ThreadDescriptor& desc = m_threads.value(threadName); if (!m_threads.contains(threadName)) { qWarning() << "Thread" << threadName << "not registered"; return false; }
// Wait for state change or timeout while (desc.state != targetState) { if (!m_waitCond.wait(&m_mutex, timeoutMs)) { qWarning() << "Waiting for thread" << threadName << "timeout (target state:" << stateToString(targetState) << ")"; return false; } }
return true;}
void ThreadMiddleware::processWaitingThreads() { QMutexLocker locker(&m_mutex); for (auto& [name, desc] : m_threads) { if (desc.state == ThreadState::Waiting) { // Check if all dependencies are complete bool dependenciesMet = true; for (const QString& dep : desc.dependencies) { if (m_threads.value(dep).state != ThreadState::Stopped) { dependenciesMet = false; break; } } if (dependenciesMet) { updateThreadState(name, ThreadState::Running); // Trigger running } } }}
Usage Example
1. Define Functional Thread (Data Acquisition Thread)
// DataAcquisitionThread.h#pragma once#include "BaseFunctionThread.h"
class DataAcquisitionThread : public BaseFunctionThread { Q_OBJECTpublic: explicit DataAcquisitionThread(const QString& name, QObject* parent = nullptr) : BaseFunctionThread(name, parent) {}
protected: void run() override { if (!initialize()) { // Initialization (interact with middleware) emit errorOccurred("initialization failed"); return; } startTask(); // Execute task (interact with middleware) }
void startTask() override { QThread::msleep(2000); // Simulate data acquisition (2 seconds) emit taskCompleted(); // Notify middleware that the task is complete }};
2. Integrate Middleware in Main Program
// main.cpp#include <QCoreApplication>#include <QDebug>#include "ThreadMiddleware.h"#include "DataAcquisitionThread.h"#include "AlgorithmProcessingThread.h"
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv);
// Get middleware instance ThreadMiddleware* middleware = ThreadMiddleware::instance();
// Create and register data acquisition thread DataAcquisitionThread* daThread = new DataAcquisitionThread("DataAcquisition"); ThreadDescriptor daDesc("DataAcquisition", "DataAcquisition"); middleware->registerThread(daThread, daDesc);
// Create and register algorithm processing thread (depends on data acquisition thread) AlgorithmProcessingThread* apThread = new AlgorithmProcessingThread("AlgorithmProcessing"); ThreadDescriptor apDesc("AlgorithmProcessing", "AlgorithmProcessing", {"DataAcquisition"}); middleware->registerThread(apThread, apDesc);
// Connect middleware signals QObject::connect(middleware, &ThreadMiddleware::threadStateChanged, [](const QString& name, ThreadState state) { qDebug() << "Thread" << name << "state changed to:" << stateToString(state); }); QObject::connect(middleware, &ThreadMiddleware::allThreadsStopped, []() { qDebug() << "All threads have stopped, exiting program"; QCoreApplication::quit(); });
// Initialize and start threads if (middleware->initializeThreads()) { middleware->startThread("DataAcquisition"); // Start data acquisition thread middleware->startThread("AlgorithmProcessing"); // Start algorithm processing thread (automatically waits for data acquisition to complete) }
return app.exec();}
Conclusion
This middleware provides a general, safe, and flexible management solution for multithreading collaborative scenarios by constraining thread lifecycles through a state machine, implementing inter-thread communication via signal-slot, and ensuring thread safety with mutexes and condition variables. It is suitable for fields requiring high-precision thread collaboration, such as industrial control, data processing, and device linkage.
