|
@@ -0,0 +1,190 @@
|
|
|
+#include "threadcontroller.h"
|
|
|
+#include <QDebug>
|
|
|
+
|
|
|
+#if defined(Q_OS_WIN32)
|
|
|
+#include <windows.h>
|
|
|
+#include <tlhelp32.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#include <QPointer>
|
|
|
+
|
|
|
+/* 获取线程数 */
|
|
|
+int ThreadUtility::GetThreadCount(int processID)
|
|
|
+{
|
|
|
+#if defined(Q_OS_WIN32)
|
|
|
+ PROCESSENTRY32 pe32;
|
|
|
+ pe32.dwSize = sizeof(pe32);
|
|
|
+
|
|
|
+ HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
|
|
|
+ if (hProcessSnap == INVALID_HANDLE_VALUE)
|
|
|
+ {
|
|
|
+ qDebug()<<"CreateToolhelp32Snapshot 调用失败";
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ BOOL bMore = ::Process32First(hProcessSnap, &pe32);
|
|
|
+
|
|
|
+ //printf("%-30s %-20s %-20s %-15s\n","szExeFile","th32ProcessID","th32ParentProcessID","cntThreads");
|
|
|
+ while(bMore)
|
|
|
+ {
|
|
|
+ //printf("%-30s ",pe32.szExeFile);
|
|
|
+ //printf("%-20d ",pe32.th32ProcessID);
|
|
|
+ //printf("%-20d",pe32.th32ParentProcessID);
|
|
|
+ ////显示进程的线程数
|
|
|
+ //printf("%-15d\n",pe32.cntThreads);
|
|
|
+ //int pid = getpid();
|
|
|
+ bMore = Process32Next(hProcessSnap, &pe32);
|
|
|
+ if(static_cast<int>(pe32.th32ProcessID) == processID)
|
|
|
+ {
|
|
|
+ //qDebug()<<"进程名称 = "<<QString::fromWCharArray(pe32.szExeFile);
|
|
|
+ //qDebug()<<"进程ID = "<<pe32.th32ProcessID;
|
|
|
+ //qDebug()<<"线程数量 = "<<pe32.cntThreads;
|
|
|
+ return static_cast<int>(pe32.cntThreads);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+#elif defined(Q_OS_LINUX)
|
|
|
+ return -1;
|
|
|
+#endif
|
|
|
+}
|
|
|
+bool ThreadUtility::BlockExitThread(QThread *thread, unsigned long msecs)
|
|
|
+{
|
|
|
+ thread->quit();
|
|
|
+ thread->requestInterruption();
|
|
|
+ bool isSuccess = false;
|
|
|
+ if(!thread->wait(msecs))
|
|
|
+ {
|
|
|
+ qDebug()<<"线程异常结束"<<thread;
|
|
|
+ thread->terminate();
|
|
|
+ if(!thread->wait(20000)) qDebug()<<"线程terminate异常";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ qDebug()<<"线程正常结束"<<thread;
|
|
|
+ isSuccess = true;
|
|
|
+ }
|
|
|
+ return isSuccess;
|
|
|
+}
|
|
|
+/* 工作线程 */
|
|
|
+ThreadWorker::ThreadWorker()
|
|
|
+ : QObject(nullptr)
|
|
|
+ , m_pWorkTimer(nullptr)
|
|
|
+ , m_bInited(false)
|
|
|
+ , m_nInterval(1000)
|
|
|
+{
|
|
|
+ m_pWorkTimer = new QTimer(nullptr);
|
|
|
+ connect(m_pWorkTimer, &QTimer::timeout, this, &ThreadWorker::OnWorkTimer, Qt::QueuedConnection);
|
|
|
+ connect(this, &ThreadWorker::sig_StartWorkTimer, this, &ThreadWorker::OnStartWorkTimer, Qt::QueuedConnection);
|
|
|
+
|
|
|
+ QThread *pHostThread = new QThread(nullptr);
|
|
|
+ pHostThread->start();
|
|
|
+ moveToThread(pHostThread); /* 将本实例移动到新线程中,其实就是将事件循环等移过去 */
|
|
|
+ m_pWorkTimer->moveToThread(pHostThread); /* 将定时器移到新线程中,定时器触发的槽函数就会运行在新线程中 */
|
|
|
+ /*----------------------------------------------------------------
|
|
|
+ * 对线程执行quit会发生: 结束线程的事件循环(线程里的对象不再能接受任何信号, 除了deleteLater), 发送finished信号
|
|
|
+ * 宿主线程对象和工作对象都在同一个线程, 所以用DirectConnection
|
|
|
+ * 这里是一个序列: 对线程执行quit -> 线程发送finished信号 -> 工作对象释放 -> 线程对象释放
|
|
|
+ ----------------------------------------------------------------*/
|
|
|
+ connect(pHostThread, &QThread::finished, this, &ThreadWorker::deleteLater, Qt::DirectConnection);
|
|
|
+ connect(this, &ThreadWorker::destroyed, pHostThread, &QThread::deleteLater, Qt::DirectConnection);
|
|
|
+
|
|
|
+ WorkerCollector::Instance()->AddWorker(this);
|
|
|
+}
|
|
|
+
|
|
|
+ThreadWorker::~ThreadWorker()
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+//在子线程执行(m_pWorkTimer已被移至线程)
|
|
|
+void ThreadWorker::OnStartWorkTimer(int msecs)
|
|
|
+{
|
|
|
+ m_nInterval = (msecs==-1)?10:msecs;
|
|
|
+ if(msecs == -1) m_pWorkTimer->setSingleShot(true);
|
|
|
+ m_pWorkTimer->start(0);
|
|
|
+}
|
|
|
+
|
|
|
+//Start方法被主线程调用, 内容在主线程执行
|
|
|
+void ThreadWorker::Start(int interval)
|
|
|
+{
|
|
|
+ QMutexLocker lockerInited(&m_mutexInited);
|
|
|
+ m_bInited = false;
|
|
|
+ emit sig_StartWorkTimer(interval);
|
|
|
+}
|
|
|
+
|
|
|
+void ThreadWorker::NonBlockStop()
|
|
|
+{
|
|
|
+ QThread *pThread = dynamic_cast<QThread*>(thread());
|
|
|
+ if(pThread == nullptr) return;
|
|
|
+ pThread->quit();
|
|
|
+ pThread->requestInterruption();
|
|
|
+}
|
|
|
+//该方法只能被主线程调用
|
|
|
+//否则报错: Thread tried to wait on itself
|
|
|
+bool ThreadWorker::BlockStop(unsigned long msecs)
|
|
|
+{
|
|
|
+ return ThreadUtility::BlockExitThread(thread(), msecs);;
|
|
|
+}
|
|
|
+
|
|
|
+void ThreadWorker::SetInterval(int interval)
|
|
|
+{
|
|
|
+ m_pWorkTimer->setInterval(interval);
|
|
|
+}
|
|
|
+
|
|
|
+//OnWorkTimer在其他线程执行
|
|
|
+void ThreadWorker::OnWorkTimer()
|
|
|
+{
|
|
|
+ m_pWorkTimer->setInterval(m_nInterval);
|
|
|
+ /* 初始化锁 */
|
|
|
+ m_mutexInited.lock();
|
|
|
+ if(!m_bInited)
|
|
|
+ {
|
|
|
+ m_bInited = true;
|
|
|
+ DoInit();
|
|
|
+ }
|
|
|
+ m_mutexInited.unlock();
|
|
|
+
|
|
|
+ DoWork();
|
|
|
+ emit sig_Ticked(this);
|
|
|
+ //工作对象非循环且内容执行完毕
|
|
|
+ if(m_pWorkTimer->isSingleShot())
|
|
|
+ {
|
|
|
+ NonBlockStop();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //主动调用NonBlockStop或BlockStop且未等待超时
|
|
|
+ if(thread()->isInterruptionRequested())
|
|
|
+ {
|
|
|
+ m_pWorkTimer->stop();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+WorkerCollector::CollectorGarbo WorkerCollector::garbo;
|
|
|
+WorkerCollector* WorkerCollector::sm_pInstance = new WorkerCollector(); //初始化静态单例(饿汉)
|
|
|
+
|
|
|
+//在这里释放那些: 直到程序结束还没有被释放的工作对象
|
|
|
+WorkerCollector::~WorkerCollector()
|
|
|
+{
|
|
|
+ sm_pInstance = nullptr;
|
|
|
+ auto pred = [](QPointer<ThreadWorker> x){return x != nullptr;};
|
|
|
+ QList<QPointer<ThreadWorker>> remainWorkers;
|
|
|
+ std::copy_if(m_listWorkers.begin(), m_listWorkers.end(), std::back_inserter(remainWorkers), pred);
|
|
|
+ qDebug() << "线程管理器释放: 待释放工作对象个数" << remainWorkers.count();
|
|
|
+ int counter = 0;
|
|
|
+ for(QPointer<ThreadWorker> pWorker: remainWorkers)
|
|
|
+ {
|
|
|
+ //注意: 这里如果是停止超时的情况, 说明工作对象正在执行内容, 直接调用delete可能会导致崩溃
|
|
|
+ //而且这里不能使用deleteLater来释放工作对象, 因为线程的事件循环已经退出了
|
|
|
+ if(!pWorker->BlockStop(5000)) continue;
|
|
|
+ delete pWorker;
|
|
|
+ counter++;
|
|
|
+ }
|
|
|
+ qDebug()<<"已释放工作对象: "<<counter;
|
|
|
+ m_listWorkers.clear();
|
|
|
+}
|
|
|
+
|
|
|
+void WorkerCollector::AddWorker(ThreadWorker *worker)
|
|
|
+{
|
|
|
+ QPointer<ThreadWorker> pWorker(worker);
|
|
|
+ m_listWorkers.append(pWorker);
|
|
|
+}
|
|
|
+
|