From: Wolfgang Bangerth Date: Sun, 21 Jul 2024 22:08:56 +0000 (-0600) Subject: Add another test for TaskResult::try_emplace_task(). X-Git-Tag: v9.6.0-rc1~25^2 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53479565837a84088ce73b4470b0dd429125abe7;p=dealii.git Add another test for TaskResult::try_emplace_task(). --- diff --git a/tests/multithreading/task_result_04.cc b/tests/multithreading/task_result_04.cc new file mode 100644 index 0000000000..d17d58f617 --- /dev/null +++ b/tests/multithreading/task_result_04.cc @@ -0,0 +1,79 @@ +// ------------------------------------------------------------------------ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2009 - 2024 by the deal.II authors +// +// This file is part of the deal.II library. +// +// Part of the source code is dual licensed under Apache-2.0 WITH +// LLVM-exception OR LGPL-2.1-or-later. Detailed license information +// governing the source code and code contributions can be found in +// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II. +// +// ------------------------------------------------------------------------ + + +// Test TaskResult::try_emplace_task(). Make sure that any second call +// to this function does not actually change anything. + +#include + +#include "../tests.h" + + + +int +main() +{ + initlog(); + + // Create a default-constructed TaskResult object not associated with a task: + Threads::TaskResult task_result; + + // Next run 10 threads in parallel that all try to set a task + // object. Calling TaskResult::operator=() will not work because + // some thread will try to set a task while there is already a + // running task, and that is considered an error. + // + // On the other hand, exactly one of the threads will succeed in + // emplacing a task with try_emplace_task(). + // + // To make things a bit more interesting, and make sure that there + // really is contention, we let all the threads spin until a + // condition variable changes state. In other words, they will all + // try *at more or less the same time* to call try_emplace_task(). + std::atomic condition(false); + + const unsigned int n_threads = 10; + std::list threads; + for (unsigned int t = 0; t < n_threads; ++t) + threads.emplace_back(std::thread([&]() { + while (condition.load() == false) + /* keep checking */; + + task_result.try_emplace_task([]() { return 42; }); + + // Now also try to emplace a task that will have a different + // result: 12 instead of 42. None of these try_emplace_back() + // calls will succeed because at the time we reach them, at + // least one of the previous calls to the function returning 42 + // will have succeeded (on this or another thread). As a + // consequence, the task result will have to be 42, regardless + // of what we set here. + task_result.try_emplace_task([]() { return 12; }); + })); + + // Now let all of these threads go to work: + condition = true; + + // Wait for all of these threads to finish trying to emplace a task: + for (auto &t : threads) + t.join(); + + // Wait for that background task to finish, then get its + // value: + deallog << task_result.value() << std::endl; + + // Ensure that we can continue to ask for the return value: + deallog << task_result.value() << std::endl; +} diff --git a/tests/multithreading/task_result_04.output b/tests/multithreading/task_result_04.output new file mode 100644 index 0000000000..85ecae61a0 --- /dev/null +++ b/tests/multithreading/task_result_04.output @@ -0,0 +1,3 @@ + +DEAL::42 +DEAL::42