惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Vulnerabilities – Threatpost
有赞技术团队
有赞技术团队
小众软件
小众软件
O
OpenAI News
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
MongoDB | Blog
MongoDB | Blog
阮一峰的网络日志
阮一峰的网络日志
Hacker News: Ask HN
Hacker News: Ask HN
D
Docker
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
C
CERT Recently Published Vulnerability Notes
L
LINUX DO - 最新话题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Hacker News - Newest:
Hacker News - Newest: "LLM"
G
Google Developers Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY
S
Schneier on Security
T
Tor Project blog
Spread Privacy
Spread Privacy
PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
The Exploit Database - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
Apple Machine Learning Research
Apple Machine Learning Research
T
Threat Research - Cisco Blogs
T
Troy Hunt's Blog
罗磊的独立博客

heise online News

Machine Learning mit Python – KI und Deep Learning in 5 Sessions erklärt Porsche-Chef Leiters plant umfassenden Konzernumbau Studie: KI bleibt oft im Testlauf stecken iX-Workshop: Grundlagen und Prinzipien eines modernen IT-Managements Missing Link: Aus für De-Mail – warum das „@“ das eingekringelte „e“ besiegte Top 10: Android Auto & Carplay nachrüsten – das beste Display fürs Auto im Test BOS-Funk: ETSI standardisiert Funk für Behörden Repair-Cafés jubeln: Bundestag beschließt Ökodesign-Reform für Nachhaltigkeit Google wehrt sich gegen Monopol-Urteil CERN-Rat beschließt Strategie-Update: FCC-ee soll LHC-Nachfolger werden Product Owner AI Day 2026: Konferenz und Workshop für KI im Produktmanagement Taskforce sieht keine Knappheit bei Kerosin Aus dem Weg! E-Scooter Navee UT5 Max mit Kuhfänger und brachialer Power im Test Krankenhaus-IT: Geldmangel und schlechte Prozesse gefährden Digitalisierung „The Boroughs“: Opa entdeckt Stranger Things iX-Workshop: Lokales Active Directory gegen Angriffe absichern Google Pics und Tiger-Selfies – die Fotonews der Woche 21/2025 Fitbit-App bekommt großes Update auf Version 5.0 und heißt jetzt Google Health Zwischen Wellen, Weite und Wissenschaft: Die Bilder der Woche 21 Sonnenenergie effizient speichern und nutzen | c’t uplink Cyberangriff auf Abrechnungsdienstleister betrifft viele Kliniken Lizenzstreit und Cloud-Zwang: Bambu Lab unter massivem Druck Vom Postweg ins BundID-Konto: Bundestag stimmt für digitales Führungszeugnis Windows 11 ist ein kompletter Verkehrsunfall Europol legt VPN-Dienst lahm TV-Deals zur WM: Die besten Fernseher von OLED bis XXL zum Tiefstpreis Nvidia will mit Vera-Prozessoren nach der CPU-Krone greifen Googles XR-Brillen auf der I/O: Project Aura & Prototyp ausprobiert Proxmox VE 9.2 mit Dynamic Load Balancer und Linux Kernel 7.0 Großstadt blockiert Überwachungssoftware Palantir Gelöscht und doch nicht weg: Signal speichert Nachrichten länger als erwartet SADAS: Neue Software warnt Fahrer vor Gefahrenzonen im Straßenraum Drei Fragen und Antworten: Wann sich KI-Coding wirklich rechnet Metas KI-Brillen helfen Blinden im Alltag – und werfen neue Fragen auf Fotoanbieter Portraitbox: Erpressung nach Sicherheitsvorfall? KI-Update: Google I/O-Fazit, Anthropic, Nvidia, Gehirn und KI-Parallelen Avatare und Augmented Reality: Apple schnappt sich kleines Start-up Won’t fix! – Teil 1: Warum Softwareschätzungen so zuverlässig falsch sind Virtual OS Museum: Über 1700 alte Betriebssysteme in einer VM Navee XT5 Max Test: Brachialer E-Scooter mit 2200 Watt ist Outdoor-Testsieger Airbnb personalisiert App mit KI IT-Ausfälle immer teurer für große Unternehmen Betrug im App Store: Apple stoppt laut eigenen Angaben Milliarden-Verluste TGIQF: Das Quiz rund um Hubschrauber Verbraucherschützer fordern Schadensersatz für Nutzer bei Smart-Meter-Problemen Citroën kündigt Elektroauto mit dem Namen „2CV“ an Software Testing: So ändert Agentic Engineering die Softwareentwicklung Post zum Freitag: Clever durch den Urlaub – schlauer reisen, entspannter surfen iX-Workshop: Sicherer Betrieb von Windows 11 im Unternehmen Camunda: ProcessOS optimiert Geschäftsprozesse mit KI macOS kann bald barrierefreien Sony-Access-Controller nutzen Elektro-Sportenduro Radian EXR vorgestellt: Viel Kraft aus Wechselakkus Voice Control in iOS 27: Accessibility-Feature sagt Siri-App-Steuerung voraus Stellantis stellt neue Plattform für neuen Strategieplan vor Spotify: Neue Desktop-App erstellt personalisierte KI-Podcasts Zum Jahresende: Bundestag beschließt Ende der De-Mail Bluesky: Russische Akteure kapern angeblich Accounts und verbreiten Propaganda Dell PowerEdge: Bis zu 70 Prozent mehr Leistung für Rechenzentren Forscher nutzen Vakuumprozess zur Herstellung von effizienten Tandemsolarzellen Jubiläum: Apple Retail Stores seit 25 Jahren im Geschäft Spotify kündigt KI-generierte Remixe und Podcasts an IT Summit 2026: heise-Konferenz zu Digitaler Souveränität „Helldivers 2“: DLSS 4.5, FSR 4 und XeSS 3.0 kommen am 27. Mai Passend zur Fußball-WM: Apple verbessert Sports-App „Gemini built in“: Google bietet Referenzdesigns für Smart-Home-Geräte an Neu in .NET 10.0 [24]: LINQ-Operatoren RightJoin() und LeftJoin() in EF Core Drei „Tomb Raider“-Klassiker im Epic Games Store kostenlos Apache-Airflow-Komponenten: Angreifer können Datenbank modifizieren Notepad++: Update bessert Schwachstelle im Installer aus Halbleiter-Ökosystem: Studie beschreibt EU-Problemzonen Stellantis-Umbau: Fokus auf Kernmarken und Kapazitätsabbau in Europa Cisco stopft Sicherheitsleck mit Höchstwertung in Secure Workload „GTA 6“ erscheint wie geplant am 19. November Samsung: Abstimmung über Boni von Hunderttausenden Euro pro Mitarbeiter Vier Arme sind besser als zwei: Humanoider Roboter für die Schwerelosigkeit Kopfhörer mit KI-Chip made in Germany: Soundcore Liberty 5 Pro ausprobiert iX-Workshop: Sicheres Active Directory – Adminrechte mit Tiering schützen Destiny-Ära endet: Bungie beendet Entwicklung von „Destiny 2" Riesenrakete Starship: SpaceX hat den nächsten Testflug erneut verschoben Trend Micro Apex One und Langflow: Warnung vor Angriffen Kann WhatsApp verschlüsselte Nachrichten einsehen? Texas reicht Klage ein Passiv-PC Arctic senza AI 370 im Test: Schnell, lautlos, unsichtbar Warhammer Skulls 2026: Die volle Ladung „Warhammer“-Videospiele Freitag: Robotaxi-Probleme in den USA, Australiens Kinderschutz-Strafe gegen X Vorsicht, Kunde! – Wenn der Gutschein plötzlich wertlos wird Waymo stoppt Autobahnfahrten und Robotaxi-Dienste in Städten mit Starkregen Privacy Guardrail: Chrome-Erweiterung will sensible Daten vor Chatbots schützen Mit dem Deutschland-Stack samt Zertifizierung zur digitalen Souveränität X kooperierte nicht mit Behörde: Höhere Strafe in Australien GMX bringt KI ins Postfach: Wir haben den Assistenten ausprobiert Digitale Souveränität: OpenDesk laut Studie keine volle Microsoft-Alternative Digitale Souveränität: Bund vergibt 250-Millionen-KI-Cloud-Auftrag Kupfer-Glas-Migration: „Homes connected macht keinen Sinn“ Teure Kultur: Justizministerin Hubig kündigt Kampf gegen Ticketwucher an Top 10: Der beste Wireless Charger mit Qi2 im Test – Magsafe-Ladegerät für alle AMDs offizieller Mini-PC kostet 3999 US-Dollar WordPress: Offizielles Plug-in bindet Blogs direkt ins Bluesky-Protokoll ein KI beweist: Mathematiker lagen falsch re:publica: Große Fragen, kaum Antworten Fritz Labor 8.40 bereitet Fritzboxen auf Matter vor
Asynchrone Programmierung – Teil 4: Qt6 mit QPromise und QFuture
Martin Meeser · 2026-06-09 · via heise online News

Das Framework Qt unterstützt mit seinem tief in der Architektur verankerten Event-System und dem Signal-Slot-Mechanismus seit jeher Entwicklerinnen und Entwickler bei der asynchronen Programmierung. Diese Möglichkeiten hat der vorangegangene Teil unserer Serie vorgestellt.

QFuture ist ein neueres Qt-Konstrukt, das das Konzept des „thennables“ – der .then()-Methoden – aus anderen Sprachen aufnimmt (z. B. Promise in JavaScript, CompletableFuture in Java oder Task in C#). Es erlaubt mit QFuture::then() das Ausführen und Hintereinanderschalten von asynchronen Funktionen, unabhängig von Threads, beispielsweise um Benutzeroberflächen asynchron zu aktualisieren.

In Qt tritt ein lesendes, konsumierendes QFuture immer als die eine Seite der gleichen Medaille auf. Auf der schreibenden, produzierenden Seite steht das QPromise. Entwicklerinnen und Entwickler können den Zustand des Promise-Future-Paares detailliert steuern: starten (QPromise::start()), aussetzen (QPromise::suspend()), beenden (QPromise::finish()) oder abbrechen (QPromise::cancel()). Schließlich können Developer nicht nur einen Rückgabewert, sondern beliebig viele setzen (QPromise::addResult()). Mit der QPromise-/QFuture-API haben sie eine praktische Schnittstelle, um Benutzer- sowie Logik-Schichten effektiv zu trennen und Fortschritte an die Bedienoberfläche zu melden.

Die Klasse QFutureWatcher liefert einen Mechanismus, um die QFuture-Funktionalität mit dem im vorangegangenen Artikel beschriebenen Signal-/Slot-Mechanismus zu verbinden. Das folgende Listing 1 zeigt ein Beispiel für die grundlegenden Funktionsweisen.

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    QFutureWatcher<int> watcher;
    QObject::connect(&watcher, &QFutureWatcher<int>::started, []()
    {
        qInfo() << "future started ";
    });

    QObject::connect(&watcher, &QFutureWatcher<int>::resultReadyAt, [&watcher](int i)
    {
        qInfo() << "result ready" << i << "=" << watcher.future().resultAt(i);
    });

    QObject::connect(&watcher, &QFutureWatcher<int>::finished, [&watcher, &app]()
    {
        qInfo() << "future finished ";
        for (int i = 0; i < watcher.future().resultCount(); ++i)
        {
            qInfo() << "Final result" << i << "=" << watcher.future().resultAt(i);
        }
        app.quit();
    });

    QPromise<int> promise;
    QFuture<int> future = promise.future();
    watcher.setFuture(future);

    QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();
        QThread::sleep(1);
        promise.addResult(10);
        QThread::sleep(1);
        promise.addResult(20);
        QThread::sleep(1);
        promise.finish();
    });

    return app.exec();
}

Listing 1: Einfaches Beispiel für die Verwendung von QPromise, QFuture und QFutureWatcher.

Neben QFutureWatcher bietet die Klasse QFuture eine Fluent-API an, mit der man Futures hintereinander schaltet (das angesprochene „thennable“ bzw. auch als „chaining“ bezeichnet): Entwickler legen mit then() einen Nachfolger fest, wobei eine zweite Verwendung von then() den bisherigen Nachfolger überschreibt, sodass es immer nur einen Nachfolger geben kann. Außerdem löst die erste Verwendung von addResult des zugrunde liegenden Promise then() aus, und nicht etwa promise.finish(). Ein Abbruch des Promise mit cancel() aktiviert den Callback onCancelled (siehe Listing 2 unten).

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    QPromise<int> promise;
    QFuture<int> future = promise.future();

    QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();
        qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "started";
        QThread::sleep(1);
        promise.addResult(1);  // triggert then()
        QThread::sleep(1);
        // promise.cancel(); // triggert onCanceled()
        promise.addResult(2); // kein Effekt auf then()
        promise.finish();// kein Effekt auf then()
    });

    future
    .onCanceled([]{/*...*/ return -1;})
    .then([](int result1)
    {
        qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "result" << result1;
    });


    return app.exec();
}

Listing 2: Beispiel für das Auslösen von then() und onCancelled().

Die Methode then() ist sowohl beim Parameter als auch dem Rückgabewert generisch. Das bedeutet konkret: Bei QFuture<T> hat das then-Callable einen Parameter vom Typ T. Der Rückgabetyp, den der Entwickler innerhalb des then-Callable verwendet, ist der Rückgabetyp des Futures, das wiederum mit then() in die verkettete Abfolge gehängt werden kann, siehe Listing 3:

void myFunc(QString val){/*...*/ return;}


QFuture<int> future = // siehe Listing 12
QFuture<void> future2 = future.then([](int result1)
{
   return QString("fortytwo");
}).then(myFunc);

Listing 3: Beispiel für Future-Chaining mit then().

Falls innerhalb eines Future oder eines then()-Blocks eine Exception auftritt, wird diese an den Callback onFailed() geleitet. Dabei gilt die Regel, dass die Exception in der Kette weiter wandert, bis sie ein passender onFailed-Callback erreicht. Wenn man Programmteile in Arbeiter-Threads auslagert, muss man dort Exceptions korrekt auffangen und an promise.setException() übergeben. Nur dann funktioniert die Methode onFailed wie erwartet, siehe Listing 4:

QThreadPool::globalInstance()->start([&promise]()
    {
        promise.start();

        try
        {
            throw std::runtime_error("error from f1");
            promise.addResult(42); // das wird nicht erreicht
        }
        catch (const std::exception& ex)
        {
            promise.setException(std::current_exception());
        }
    });
    future.then([](int i)
    {
        // ...
    }).onFailed([](const std::exception& ex)
    {
        qInfo() << ex.what();
    });

    QTimer::singleShot(200, &app, &QCoreApplication::quit);

Listing 4: Korrekte Verarbeitung von Exceptions in Arbeits-Threads mit Promise.

Entwickler können auch mehrere onFailed mit einem Future verwenden. In diesem Fall wird das erste passende aufgerufen. Dabei ist die Reihenfolge relevant: Beispielsweise wird in Listing 5 das zweite onFailed nie erreicht, da im vorherigen bereits die darüber liegende Klasse abgefangen wurde.

future.then([](int res) {
    // ...
    throw std::runtime_error("Exception");
}).onFailed([](const std::exception &e) {
    // dieses Callback wird ausgeführt
}).onFailed([](const std::runtime_error &e) {
});

Listing 5: Verwendung mehrerer onFailed-Callbacks

Innerhalb der Funktion, die onFailed verarbeitet, können Entwickler auch einen Rückgabewert angeben. Die Kette wird dann mit diesem Wert fortgeführt, siehe Listing 6:

QFuture<int> future = ...
future
.onFailed([](const QException& ex)
{
    return -1;
})
.then([](int i)
{
    // im Fehlerfall ist i=-1
})

Listing 6: Fortführung der then()-Kette im Fehlerfall.

Wenn kein passender Callback onFailed vorhanden ist, wird die Exception von demjenigen Thread, in dem sie auftrat, an den aufrufenden Thread weitergeleitet und muss dort entsprechend abgefangen werden (Error Propagation), siehe Listing 7:

auto resultFuture = future.then([](int res) {
    ...
    throw Error("message");
    ...
}).onFailed([](const std::exception &e) {
    // wird nicht aufgerufen
}).onFailed([](const QException &e) {
    // wird nicht aufgerufen
});

try {
    auto result = resultFuture.result();
} catch(Error er) {
    // dieser Teil wird aufgerufen
}

Listing 7: Propagation einer Exception.

Die bisher gezeigte Verwendung von then() führt Folgefunktionen standardmäßig in dem Thread aus, in dem das ursprüngliche QFuture lief. Entwickler können aber auch mit einem Parameter den Thread für die Folgefunktion bestimmen. Übergeben sie als Parameter ein QObject, wird dessen zugeordneter QThread verwendet. Bei einen QThreadPoolkommt dieser zum Einsatz.

Schließlich können Developer auch ein Argument vom Typ QtFuture::Launch übergeben: Die weitere Bestimmung Sync entspricht dem beschriebenen Standardfall (gleicher Thread wie Aufrufer), während Async automatisch den globalen Threadpool verwendet und Inherit die Einstellung des Vorgängers, siehe Listing 8:

// Standardfall, kein Parameter, entspricht Sync)
auto f1 = base.then([](int i) { ... });
auto f2 = f1.then(QtFuture::Launch::Sync, [](int i) { ... });

// QObject => Ausführung im Thread des QObjects
auto f3 = f1.then(&obj, [](int i) { ... });

// QThreadPool => Ausführung im angegebenen Pool
auto f4 = f2.then(&customPool, [](int i) { ... });

// Launch::Async => globaler Threadpool
auto f5 = f4.then(QtFuture::Launch::Async, [](int i) { ... });

// Launch::Inherit: erbt Thread des Vorgängers
auto f6 = f5.then(QtFuture::Launch::Inherit, [](int i) { … });

Listing 8: Bestimmung des Threads mit then(...)

Der Namespace QtFuture enthält darüber hinaus einige nützliche Hilfsfunktionen für Futures. Mit den Funktionen QtFuture::makeReady… erstellen Entwicklerinnen und Entwickler ein Future, das bereits im Status beendet ist (QFuture.isFinished() liefert true). makeReadyVoidFuture erzeugt ein beendetes Future ohne Wert (QFuture<void>), makeReadyValueFuture(T) entsprechend ein QFuture<T> und makeReadyRangeFuture ein beendetes QFuture<T>, das mehrere Ergebnisse besitzt. makeExceptionalFuture schließlich erstellt ein beendetes QFuture, das eine Exception beinhaltet.

Diese Funktionen sind nützlich, wenn man bei einer Funktion anhand von Parametern überprüfen möchte, ob eine Bearbeitung als QFuture überhaupt möglich oder sinnvoll ist. Sofern dies nicht der Fall ist, gibt die Funktion direkt ein beendetes QFuture zurück, siehe Listing 9:

QFuture<int> createIntFuture(int a)
{
    if (a <= 0)
    {
        return QtFuture::makeReadyValueFuture(0);
    }

    QPromise<int> promise;
    QFuture<int> result = promise.future();
    QThreadPool::globalInstance()->start([promise = std::move(promise), a]() mutable
    {
        promise.start();
        QThread::sleep(500);
        promise.addResult(a + 1);
        promise.finish();
    });
}

Listing 9: Verwenden eines bei der Erstellung beendeten Futures mit makeReadyValueFuture.

Eine weitere nützliche Funktion ist QtFuture::whenAll(), die ein QFuture erzeugt, das beendet wird, wenn alle als Parameter übergebenen QFuture beendet sind. Die QFuture können verschiedene Template-Typen haben, dementsprechend ist der Rückgabetyp von whenAll ein QFuture mit einer Liste vom Typ std::variant.

Developer müssen hier noch auf die Besonderheit achten, dass beim Chaining mit then() die Nachfolgefunktion auf dem Thread läuft, dessen Future als Letztes beendet wurde. Dies kann, wie bereits beschrieben, ein Parameter für then() explizit festlegen, siehe Listing 10:

QFuture<int> f_int = createIntFuture();
QFuture<QString> f_qstring = createStringFuture();
QFuture<void> f_void = createVoidFuture();

using MyFuturesVariant = std::variant<QFuture<int>, QFuture<QString>, QFuture<void>>;

QFuture<QList<MyFuturesVariant>> f_whenAll = QtFuture::whenAll(f_int, f_qstring, f_void);
f_whenAll.then(/*QtFuture::Launch::Async*/, [](const
    QList<MyFuturesVariant>& results)
{
    ...
});

Listing 10: Beispiel für QtFuture::whenAll(...)

QtFuture::whenAny() erzeugt ein QFuture, das beendet wird, sobald eines der übergebenen Futures fertig ist. Beim Verketten gilt, dass die Nachfolgefunktion im Thread des zuerst beendeten Futures ausgeführt wird, sofern kein expliziter Launch-Parameter ein anderes bestimmt, siehe Listing 11:

QFuture<MyFuturesVariant> f_whenAny = QtFuture::whenAny(f_int, f_qstring, f_void);
f_whenAny.then([](const MyFuturesVariant& f)
{

});

Listing 11: Beispiel für QtFuture::whenAny(...)

Schließlich bietet die Funktion QtFuture::connect() die Möglichkeit, aus einem beliebigen Signal ein QFuture zu erzeugen, siehe Listing 12:

QTimer timer(&app);
timer.setInterval(1000);
timer.setSingleShot(true);
timer.start();

QFuture<void> timerTimeoutFuture = QtFuture::connect(&timer, &QTimer::timeout);
timerTimeoutFuture.then([]
{
    qDebug() << "QTimer timeout captured via QtFuture::connect";
});

Listing 12: Beispielhafte Verwendung von QtFuture::connect()