Library: new thread-wrapper implementation complete

- relocate some code into a dedicated translation unit to reduce #includes
- actually set the thread-ID (the old implementation had only a TODO at that point)
This commit is contained in:
Fischlurch 2023-09-26 02:32:48 +02:00
parent 67b010ba7e
commit 3fa4f02737
5 changed files with 164 additions and 69 deletions

114
src/lib/thread.cpp Normal file
View file

@ -0,0 +1,114 @@
/*
THREAD.hpp - thin convenience wrapper for starting threads
Copyright (C) Lumiera.org
2023, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file sync.cpp
** This compilation unit holds some implementation details
** of the [thread wrapper](\ref lib::Thread), relegated here
** to reduce header inclusions.
** @warning setting the thread name only works on some POSIX systems,
** and using a GNU specific addition to the libC here.
*/
#include "lib/thread.hpp"
#include "lib/format-string.hpp"
#include "lib/util.hpp"
#include <chrono>
#include <pthread.h>
using std::chrono::steady_clock;
using std::chrono_literals::operator ""ms;
namespace lib {
namespace thread{
namespace {
void
setThreadName (std::thread& handle, string name)
{
// API limitation: max 15 characters + \0
name = util::sanitise(name).substr(0, 15);
pthread_t nativeHandle = handle.native_handle();
pthread_setname_np(nativeHandle, name.c_str());
}
void
lifecycle (string format, string threadID)
{
string message = util::_Fmt{format} % threadID;
TRACE (thread, "%s", message.c_str());
}
}
template<bool autoTerm>
void
ThreadWrapper<autoTerm>::markThreadStart (string const& threadID)
{
lifecycle ("Thread '%s' start...", threadID);
setThreadName (threadImpl_, threadID);
}
template<bool autoTerm>
void
ThreadWrapper<autoTerm>::markThreadEnd (string const& threadID)
{
lifecycle ("Thread '%s' finished.", threadID);
}
template<bool autoTerm>
void
ThreadWrapper<autoTerm>::waitGracePeriod() noexcept
{
try {
auto start = steady_clock::now();
while (threadImpl_.joinable()
and steady_clock::now () - start < 20ms
)
std::this_thread::yield();
}
ERROR_LOG_AND_IGNORE (thread, "Thread shutdown wait")
if (threadImpl_.joinable())
ALERT (thread, "Thread failed to terminate after grace period. Abort.");
// invocation of std::thread dtor will presumably call std::terminate...
}
template void ThreadWrapper<true>::markThreadStart (string const&);
template void ThreadWrapper<true>::markThreadEnd (string const&);
template void ThreadWrapper<true>::waitGracePeriod () noexcept;
template void ThreadWrapper<false>::markThreadStart (string const&);
template void ThreadWrapper<false>::markThreadEnd (string const&);
template void ThreadWrapper<false>::waitGracePeriod () noexcept;
}}// namespace lib::thread

View file

@ -105,13 +105,10 @@
#include "lib/nocopy.hpp"
#include "include/logging.h"
#include "lib/meta/function.hpp"
#include "lib/format-string.hpp" ///////////////////////////OOO RLY? or maybe into CPP file?
#include "lib/result.hpp"
#include <thread>
#include <string>
#include <utility>
#include <chrono>
namespace lib {
@ -198,40 +195,9 @@ namespace lib {
} // Note: implies get_id() != std::thread::id{} ==> it is running
private:
void
markThreadStart (string const& threadID)
{
string logMsg = util::_Fmt{"Thread '%s' start..."} % threadID;
TRACE (thread, "%s", logMsg.c_str());
//////////////////////////////////////////////////////////////////////OOO maybe set the the Thread-ID via POSIX ??
}
void
markThreadEnd (string const& threadID)
{
string logMsg = util::_Fmt{"Thread '%s' finished..."} % threadID;
TRACE (thread, "%s", logMsg.c_str());
}
void
waitGracePeriod() noexcept
{
using std::chrono::steady_clock;
using std::chrono_literals::operator ""ms;
try {
auto start = steady_clock::now();
while (threadImpl_.joinable()
and steady_clock::now () - start < 20ms
)
std::this_thread::yield();
}
ERROR_LOG_AND_IGNORE (thread, "Thread shutdown wait")
if (threadImpl_.joinable())
ALERT (thread, "Thread failed to terminate after grace period. Abort.");
// invocation of std::thread dtor will presumably call std::terminate...
}
void markThreadStart (string const& threadID);
void markThreadEnd (string const& threadID);
void waitGracePeriod() noexcept;
};
}//(End)base implementation.
@ -281,7 +247,7 @@ namespace lib {
join ()
{
if (not threadImpl_.joinable())
throw error::Logic ("joining on an already terminated thread");
throw lumiera::error::Logic ("joining on an already terminated thread");
threadImpl_.join();
}

View file

@ -747,17 +747,6 @@ END
TEST "util: sanitised identifier" UtilSanitizedIdentifier_test <<END
out-lit: 'Word' --> 'Word'
out-lit: 'a Sentence' --> 'a_Sentence'
out-lit: 'trailing Withespace
out-lit: ' --> 'trailing_Withespace'
out-lit: 'with a lot
out-lit: of Whitespace' --> 'with_a_lot_of_Whitespace'
out-lit: '@with".'much (\$punctuation)[]!' --> '@with.much_(\$punctuation)'
out-lit: '§&Ω%€ leading garbage' --> 'leading_garbage'
out-lit: 'mixed Ω garbage' --> 'mixed_garbage'
out-lit: 'Bääääh!!' --> 'Bh'
out-lit: '§&Ω%€' --> ''
return: 0
END

View file

@ -26,6 +26,7 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/util.hpp"
@ -42,22 +43,16 @@ namespace test {
{
virtual void run (Arg)
{
print_clean ("Word");
print_clean ("a Sentence");
print_clean ("trailing Withespace\n \t");
print_clean ("with a \t lot\n of Whitespace");
print_clean ("@with\".\'much ($punctuation)[]!");
print_clean ("§&Ω%€ leading garbage");
print_clean ("mixed Ω garbage");
print_clean ("Bääääh!!");
print_clean ("§&Ω%€");
CHECK (sanitise ( "Word") == "Word"_expect);
CHECK (sanitise ( "a Sentence") == "a_Sentence"_expect);
CHECK (sanitise ( "trailing Withespace\n \t") == "trailing_Withespace"_expect);
CHECK (sanitise ("with a \t lot\n of Whitespace") == "with_a_lot_of_Whitespace"_expect);
CHECK (sanitise ( "@with\".\'much ($punctuation)[]!") == "@with.much_($punctuation)"_expect);
CHECK (sanitise ( "§&Ω%€ leading garbage") == "leading_garbage"_expect);
CHECK (sanitise ( "mixed Ω garbage") == "mixed_garbage"_expect);
CHECK (sanitise ( "Bääääh!!") == "Bh"_expect);
CHECK (sanitise ( "§&Ω%€") == ""_expect);
}
/** @test print the original and the sanitised string */
void print_clean (const string org)
{
cout << "'" << org << "' --> '" << sanitise(org) << "'\n";
}
};
LAUNCHER (UtilSanitizedIdentifier_test, "unit common");

View file

@ -79299,9 +79299,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695606903540" ID="ID_1827438483" MODIFIED="1695606934199" TEXT="Textuelle Thread-Kennung setzen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695606935311" ID="ID_1002758793" MODIFIED="1695606969745" TEXT="nimmt jetzt einen string...">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695606903540" ID="ID_1827438483" MODIFIED="1695688141495" TEXT="Textuelle Thread-Kennung setzen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1695606935311" ID="ID_1002758793" MODIFIED="1695688125602" TEXT="nimmt jetzt einen string...">
<richcontent TYPE="NOTE"><html>
<head>
@ -79312,10 +79312,41 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p>
</body>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695606971754" ID="ID_1204181207" MODIFIED="1695606985337" TEXT="kann man das per PTHREAD setzen?">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695606971754" ID="ID_1204181207" MODIFIED="1695688121178" TEXT="kann man das per PTHREAD setzen?">
<icon BUILTIN="help"/>
<node CREATED="1695685220762" ID="ID_850524224" MODIFIED="1695685236149" TEXT="die POSIX-L&#xf6;sung ist unklar"/>
<node CREATED="1695685236698" ID="ID_443970152" MODIFIED="1695685253886" TEXT="es gibt eine GNU-Erweiterung in der glibc">
<icon BUILTIN="idea"/>
<node CREATED="1695685262204" ID="ID_163592402" LINK="https://linux.die.net/man/3/pthread_getname_np" MODIFIED="1695685265264" TEXT="manpage"/>
<node CREATED="1695685265924" ID="ID_1458536316" LINK="https://stackoverflow.com/a/7989973" MODIFIED="1695685429000" TEXT="Stackoverflow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695685434157" ID="ID_68260611" MODIFIED="1695685446644" TEXT="Implementierung">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695688011733" ID="ID_706080445" MODIFIED="1695688040471" TEXT="Linux-spezifisch">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1695688043077" ID="ID_1889925462" MODIFIED="1695688084658">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
std::thread::native_handle() &#10236; liefert hier <font face="Monospaced" color="#ff270c">pthread_t</font>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1695688094422" ID="ID_1651431673" MODIFIED="1695688112227" TEXT="verwende pthread_setname_np() aus der Glibc"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695688145491" ID="ID_295533997" MODIFIED="1695688177623" TEXT="pr&#xfc;fen: auch individuell?">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695688164064" ID="ID_421411220" MODIFIED="1695688173273" TEXT="Eclipse: sehe den Identifier">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
<node CREATED="1695607699183" ID="ID_470294434" MODIFIED="1695607712099" TEXT="Ctor-Varianten">