BackgroundRunner

% Remco Bloemen % 2014-06-12

Usage

The usage is much like QtConcurrent::run except you return what I call a Joiner; a function that integrates the result back into the calling thread:

BackgroundRunner::run([=]() {
	
	// <Background task>
	
	return [=]() {
		
		// <Joiner>
		
	};
});

Lambda’s returning lambda’s; welcome to the world of higher-order programming!

The Background task will be run a background thread using QtConcurrent::run. You have full access to the variables from the enclosing scope, notable the this pointer, but very aware of thread safety, because everything will be run in parallel!

When it is finished it returns the Joiner, which is queued for the event loop of the calling thread. Again you have access to the this pointer, but this time we are back in the objects own thread, it is as safe to use the this pointer as in any slot.

Below is an real-world example of function in a QAbstractItemModel that uses the BackgroundRunner to calculate UI content on demand, without blocking the UI.

QString DataModel::message(uint rowId)
{
	if(cache.contains(rowId))
		return cache[rowId];
	
	// Get the row data to calculate the message
	// Let's do it here to avoid concurrency issues
	const RowData rowData = dataForRow(rowId)
	
	// Calculate the message in the background
	BackgroundRunner::run([=]() {
		
		// Code here will be run in a background thread.
		// We can now use rowData, it will be a copy of the one defined on line 8
		
		const QString message = expensiveCalculateMessage(rowData);
		
		// Add the messge to the cache and inform the model
		return [=]() {
			
			// Code here can safely access both (copies of) the result from the
			// background task, and the DataModel object. It can even emit signals!
			
			_cache[rowId] = message;
			emit refresh(rowId);
		};
	});
	
	// Show ellipsis while we are waiting for the message to be done.
	return "…";
}

Source

Remco Bloemen
Math & Engineering
https://2π.com