Utils: Introduce Barrier primitive
This primitive is going to replace the TaskTree's built-in
mechanism consisting of Wait, Condition and ConditionActivator
elements.
When combining 2 barriers, one placed in a custom storage,
and the other in a tree, it's possible to fully substitute
the Wait, Condition and ConditionActivator with the comparable
amount of code.
However, the Barrier is much more versatile, since it
makes it possible to:
1. distribute the decision about the ultimate barrier pass on the
whole tree.
In order to utilize it, increase the limit of the shared barrier
with setLimit() to the expected number of places that participate
in the decision about the ultimate barrier pass and use advance()
from multiple places in the tree. When the number of calls
to advance() reaches the limit(), the shared barrier passes
automatically.
Whenever some participant failed, so that the shared barrier
can not be passed, it may call stopWithResult(false).
Whenever some other participant decided that all the needed
data are already collected, so that the barrier may pass early,
it may call stopWithResult(true), making the remaining calls to
advance no-op.
2. wait for the same barrier from multiple places.
Before, only one WaitFor was possible for a single Condition.
3. insert multiple Barriers into one Group element.
Before, only one WaitFor could be placed in a single Group.
Provide ready-made SingleCondition and waitFor() helpers.
With the new approach, the following equivalents are provided:
- SingleBarrier (substitutes old Condition)
- WaitForBarrier() (substitutes old WaitFor)
- Barrier (substitutes old ConditionActivator)
This change replaces the mechanism introduced in
29f634a8caf69a374edb00df7a19146352a14d6f.
This change conforms to the naming scheme proposed in QTCREATORBUG-29102.
Task-number: QTCREATORBUG-29102
Change-Id: I48b3e2ee723c3b9fe73a59a25eb7facc72940c3b
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
2023-04-29 19:53:40 +02:00
|
|
|
// Copyright (C) 2023 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
|
|
|
|
|
|
#include "barrier.h"
|
|
|
|
|
|
|
|
|
|
#include "qtcassert.h"
|
|
|
|
|
|
2023-05-10 19:54:52 +02:00
|
|
|
namespace Tasking {
|
Utils: Introduce Barrier primitive
This primitive is going to replace the TaskTree's built-in
mechanism consisting of Wait, Condition and ConditionActivator
elements.
When combining 2 barriers, one placed in a custom storage,
and the other in a tree, it's possible to fully substitute
the Wait, Condition and ConditionActivator with the comparable
amount of code.
However, the Barrier is much more versatile, since it
makes it possible to:
1. distribute the decision about the ultimate barrier pass on the
whole tree.
In order to utilize it, increase the limit of the shared barrier
with setLimit() to the expected number of places that participate
in the decision about the ultimate barrier pass and use advance()
from multiple places in the tree. When the number of calls
to advance() reaches the limit(), the shared barrier passes
automatically.
Whenever some participant failed, so that the shared barrier
can not be passed, it may call stopWithResult(false).
Whenever some other participant decided that all the needed
data are already collected, so that the barrier may pass early,
it may call stopWithResult(true), making the remaining calls to
advance no-op.
2. wait for the same barrier from multiple places.
Before, only one WaitFor was possible for a single Condition.
3. insert multiple Barriers into one Group element.
Before, only one WaitFor could be placed in a single Group.
Provide ready-made SingleCondition and waitFor() helpers.
With the new approach, the following equivalents are provided:
- SingleBarrier (substitutes old Condition)
- WaitForBarrier() (substitutes old WaitFor)
- Barrier (substitutes old ConditionActivator)
This change replaces the mechanism introduced in
29f634a8caf69a374edb00df7a19146352a14d6f.
This change conforms to the naming scheme proposed in QTCREATORBUG-29102.
Task-number: QTCREATORBUG-29102
Change-Id: I48b3e2ee723c3b9fe73a59a25eb7facc72940c3b
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
2023-04-29 19:53:40 +02:00
|
|
|
|
|
|
|
|
void Barrier::setLimit(int value)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!isRunning(), return);
|
|
|
|
|
QTC_ASSERT(value > 0, return);
|
|
|
|
|
|
|
|
|
|
m_limit = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Barrier::start()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!isRunning(), return);
|
|
|
|
|
m_current = 0;
|
|
|
|
|
m_result = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Barrier::advance()
|
|
|
|
|
{
|
|
|
|
|
// Calling advance on finished is OK
|
|
|
|
|
QTC_ASSERT(isRunning() || m_result, return);
|
|
|
|
|
if (!isRunning()) // no-op
|
|
|
|
|
return;
|
|
|
|
|
++m_current;
|
|
|
|
|
if (m_current == m_limit)
|
|
|
|
|
stopWithResult(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Barrier::stopWithResult(bool success)
|
|
|
|
|
{
|
|
|
|
|
// Calling stopWithResult on finished is OK when the same success is passed
|
|
|
|
|
QTC_ASSERT(isRunning() || (m_result && *m_result == success), return);
|
|
|
|
|
if (!isRunning()) // no-op
|
|
|
|
|
return;
|
|
|
|
|
m_current = -1;
|
|
|
|
|
m_result = success;
|
|
|
|
|
emit done(success);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-10 19:54:52 +02:00
|
|
|
} // namespace Tasking
|