Files
FlaxEngine/Source/Engine/Platform/Base/ThreadBase.cpp
Ari Vuollet b0bc1fa310 Fix error when joining exited threads
The internal thread handles were cleared prematurely when attempting to join them. The handles should be also cleared when trying to kill already exited threads.
2023-01-29 21:30:01 +02:00

119 lines
3.0 KiB
C++

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "Engine/Platform/Thread.h"
#include "Engine/Threading/IRunnable.h"
#include "Engine/Threading/ThreadRegistry.h"
#include "Engine/Core/Log.h"
#include "Engine/Scripting/ManagedCLR/MCore.h"
#if TRACY_ENABLE
#include "Engine/Core/Math/Math.h"
#include <ThirdParty/tracy/Tracy.h>
#endif
Delegate<Thread*> ThreadBase::ThreadStarting;
Delegate<Thread*, int32> ThreadBase::ThreadExiting;
ThreadBase::ThreadBase(IRunnable* runnable, const String& name, ThreadPriority priority)
: _runnable(runnable)
, _priority(priority)
, _name(name)
, _id(0)
, _isRunning(false)
, _callAfterWork(true)
{
ASSERT(_runnable);
#if BUILD_DEBUG
// Cache name (in case if object gets deleted somewhere)
_runnableName = _runnable->ToString();
#endif
}
void ThreadBase::SetPriority(ThreadPriority priority)
{
// Check if value won't change
if (_priority != priority)
{
// Set new value
_priority = priority;
SetPriorityInternal(priority);
}
}
void ThreadBase::Kill(bool waitForJoin)
{
if (!_isRunning)
{
ClearHandleInternal();
return;
}
ASSERT(GetID());
const auto thread = static_cast<Thread*>(this);
// Stop runnable object
if (_callAfterWork && _runnable)
{
_runnable->Stop();
}
LOG(Info, "Killing thread \'{0}\' ID=0x{1:x}", _name, _id);
// Kill platform thread
KillInternal(waitForJoin);
ClearHandleInternal();
// End
if (_callAfterWork)
{
_callAfterWork = false;
_runnable->AfterWork(true);
}
_isRunning = false;
ThreadRegistry::Remove(thread);
}
int32 ThreadBase::Run()
{
// Setup
ASSERT(_runnable);
const auto thread = static_cast<Thread*>(this);
_id = Platform::GetCurrentThreadID();
#if TRACY_ENABLE
char threadName[100];
const int32 threadNameLength = Math::Min<int32>(ARRAY_COUNT(threadName) - 1, _name.Length());
StringUtils::ConvertUTF162ANSI(*_name, threadName, threadNameLength);
threadName[threadNameLength] = 0;
tracy::SetThreadName(threadName);
#endif
ThreadRegistry::Add(thread);
ThreadStarting(thread);
int32 exitCode = 1;
_isRunning = true;
LOG(Info, "Thread \'{0}\' ID=0x{1:x} started with priority {2}", _name, _id, ::ToString(GetPriority()));
if (_runnable->Init())
{
exitCode = _runnable->Run();
if (_callAfterWork) // Prevent from calling this after calling AfterWork since object may be deleted
_runnable->Exit();
}
LOG(Info, "Thread \'{0}\' ID=0x{1:x} exits with code {2}", _name, _id, exitCode);
// End
if (_callAfterWork)
{
_callAfterWork = false;
_runnable->AfterWork(false);
}
_isRunning = false;
ThreadExiting(thread, exitCode);
ThreadRegistry::Remove(thread);
MCore::ExitThread(); // TODO: use mono_thread_detach instead of ext and unlink mono runtime from thread in ThreadExiting delegate
// mono terminates the native thread..
return exitCode;
}