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:
parent
67b010ba7e
commit
3fa4f02737
5 changed files with 164 additions and 69 deletions
114
src/lib/thread.cpp
Normal file
114
src/lib/thread.cpp
Normal 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
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -79299,9 +79299,9 @@ Date:   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:   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ö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() ⟼ 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ü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">
|
||||
|
|
|
|||
Loading…
Reference in a new issue