Files
qt-creator/src/libs/solutions/tasking/barrier.cpp

53 lines
1.4 KiB
C++
Raw Normal View History

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"
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
// That's cut down qtcassert.{c,h} to avoid the dependency.
#define QTC_STRINGIFY_HELPER(x) #x
#define QTC_STRINGIFY(x) QTC_STRINGIFY_HELPER(x)
#define QTC_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QTC_STRINGIFY(__LINE__))
#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0)
#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0)
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);
}
} // namespace Tasking