QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsthreadingutils.h
Go to the documentation of this file.
1/***************************************************************************
2 qgsthreadingutils.h
3 --------------------------------------
4 Date : 11.9.2018
5 Copyright : (C) 2018 by Matthias Kuhn
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#ifndef QGSTHREADINGUTILS_H
17#define QGSTHREADINGUTILS_H
18
19#define SIP_NO_FILE
20
21#include "qgis_core.h"
22
23#include "qgsfeedback.h"
24
25#include <QThread>
26#include <QSemaphore>
27#include <memory>
28
35class CORE_EXPORT QgsThreadingUtils
36{
37 public:
38
55 template <typename Func>
56 static bool runOnMainThread( const Func &func, QgsFeedback *feedback = nullptr )
57 {
58 // Make sure we only deal with the vector layer on the main thread where it lives.
59 // Anything else risks a crash.
60 if ( QThread::currentThread() == qApp->thread() )
61 {
62 func();
63 return true;
64 }
65 else
66 {
67 if ( feedback )
68 {
69 // This semaphore will block the worker thread until the main thread is ready.
70 // Ready means the event to execute the waitFunc has arrived in the event loop
71 // and is being executed.
72 QSemaphore semaphoreMainThreadReady( 1 );
73
74 // This semaphore will block the main thread until the worker thread is ready.
75 // Once the main thread is executing the waitFunc, it will wait for this semaphore
76 // to be released. This way we can make sure that
77 QSemaphore semaphoreWorkerThreadReady( 1 );
78
79 // Acquire both semaphores. We want the main thread and the current thread to be blocked
80 // until it's save to continue.
81 semaphoreMainThreadReady.acquire();
82 semaphoreWorkerThreadReady.acquire();
83
84 const std::function<void()> waitFunc = [&semaphoreMainThreadReady, &semaphoreWorkerThreadReady]()
85 {
86 // This function is executed on the main thread. As soon as it's executed
87 // it will tell the worker thread that the main thread is blocked by releasing
88 // the semaphore.
89 semaphoreMainThreadReady.release();
90
91 // ... and wait for the worker thread to release its semaphore
92 semaphoreWorkerThreadReady.acquire();
93 };
94
95 QMetaObject::invokeMethod( qApp, waitFunc, Qt::QueuedConnection );
96
97 // while we are in the event queue for the main thread and not yet
98 // being executed, check all 100 ms if the feedback is canceled.
99 while ( !semaphoreMainThreadReady.tryAcquire( 1, 100 ) )
100 {
101 if ( feedback->isCanceled() )
102 {
103 semaphoreWorkerThreadReady.release();
104 return false;
105 }
106 }
107
108 // finally, the main thread is blocked and we are (most likely) not canceled.
109 // let's do the real work!!
110 func();
111
112 // work done -> tell the main thread he may continue
113 semaphoreWorkerThreadReady.release();
114 return true;
115 }
116 QMetaObject::invokeMethod( qApp, func, Qt::BlockingQueuedConnection );
117 return true;
118 }
119 }
120
121};
122
123
124#endif
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
Provides threading utilities for QGIS.
static bool runOnMainThread(const Func &func, QgsFeedback *feedback=nullptr)
Guarantees that func is executed on the main thread.