nim_duilib/base/thread/framework_thread.cpp
jiajia_deng 4933d1f2bc Remove dependency on shared
Signed-off-by: jiajia_deng <2894220@gmail.com>
2019-09-20 16:27:58 +08:00

291 lines
5.9 KiB
C++

// Copyright (c) 2011, NetEase Inc. All rights reserved.
//
// Author: rl
// Date: 2011/6/29
//
// Enhanced by: wrt(guangguang)
//
// Thread with framework(message loop)
#include "framework_thread.h"
#include "base/base_types.h"
#include "base/macros.h"
#include "base/memory/lazy_instance.h"
//#include "base/log/log.h"
namespace nbase
{
// We use this thread-local variable to record whether or not a thread exited
// because its Stop method was called. This allows us to catch cases where
// MessageLoop::Quit() is called directly, which is unexpected when using a
// Thread to setup and run a MessageLoop.
nbase::LazyInstance<nbase::ThreadLocalPointer<FrameworkThreadTlsData> > lazy_tls_data;
FrameworkThread::FrameworkThread(const char* name)
: started_(false),
stopping_(false),
loop_type_(MessageLoop::kDefaultMessageLoop),
message_loop_(NULL),
event_(false, false),
name_(name)
{
}
FrameworkThread::~FrameworkThread()
{
Stop();
}
bool FrameworkThread::Start()
{
return StartWithLoop(MessageLoop::kDefaultMessageLoop);
}
#if defined(OS_WIN)
bool FrameworkThread::StartWithLoop(const MessageLoop::Type type, Dispatcher *dispatcher)
#else
bool FrameworkThread::StartWithLoop(const MessageLoop::Type type)
#endif
{
if (message_loop_ != NULL)
return false;
loop_type_ = type;
#if defined(OS_WIN)
dispatcher_ = dispatcher;
#endif
if (Create() == false)
return false;
// Wait for the thread to start and initialize message_loop_
event_.Wait();
started_ = true;
return true;
}
#if defined(OS_WIN)
bool FrameworkThread::StartWithLoop(CustomMessageLoopFactory *factory, Dispatcher *dispatcher)
#else
bool FrameworkThread::StartWithLoop(CustomMessageLoopFactory *factory)
#endif
{
if (factory == NULL)
return false;
factory_.reset(factory);
loop_type_ = MessageLoop::kCustomMessageLoop;
#if defined(OS_WIN)
dispatcher_ = dispatcher;
#endif
if (!Create())
return false;
// Wait for the thread to start and initialize message_loop_
event_.Wait();
started_ = true;
return true;
}
#if defined(OS_WIN)
void FrameworkThread::RunOnCurrentThreadWithLoop(const MessageLoop::Type type, Dispatcher *dispatcher)
#else
void FrameworkThread::RunOnCurrentThreadWithLoop(const MessageLoop::Type type)
#endif
{
loop_type_ = type;
started_ = true;
#if defined(OS_WIN)
dispatcher_ = dispatcher;
#endif
Run();
}
void FrameworkThread::Stop()
{
if (!thread_was_started())
return;
StopSoon();
// Wait for the thread to exit.
Close();
started_ = false;
stopping_ = false;
}
void FrameworkThread::StopSoon()
{
if (stopping_ || !message_loop_)
return;
stopping_ = true;
message_loop_->PostNonNestableTask(
nbase::Bind(&FrameworkThread::DoStopSoon, this));
}
void FrameworkThread::DoStopSoon()
{
MessageLoop::current()->Quit();
SetThreadWasQuitProperly(true);
}
void FrameworkThread::Run()
{
#ifndef NDEBUG
#if defined(OS_WIN) && defined(COMPILER_MSVC)
SetThreadName(GetCurrentThreadId(), name_.c_str());
#endif
#endif
InitTlsData(this);
SetThreadWasQuitProperly(false);
{
ThreadId thread_id = Thread::CurrentId();
set_thread_id(thread_id);
// The message loop for this thread.
MessageLoop *message_loop;
if (loop_type_ == MessageLoop::kCustomMessageLoop)
message_loop = factory_->CreateMessageLoop();
else {
if (loop_type_ == MessageLoop::kIOMessageLoop)
message_loop = new IOMessageLoop;
#if defined(OS_WIN)
else if (loop_type_ == MessageLoop::kUIMessageLoop)
message_loop = new UIMessageLoop;
#endif
else
message_loop = new MessageLoop;
}
message_loop_ = message_loop;
// Let the thread do extra initialization.
// Let's do this before signaling we are started.
Init();
event_.Signal();
#if defined(OS_WIN)
message_loop_->RunWithDispatcher(dispatcher_);
#else
message_loop_->Run();
#endif // OS_WIN
// Let the thread do extra cleanup.
Cleanup();
//DCHECK(GetThreadWasQuitProperly());
// We can't receive messages anymore.
if (loop_type_ != MessageLoop::kCustomMessageLoop)
delete message_loop_;
else
{
delete message_loop_;
factory_.reset();
}
message_loop_ = NULL;
}
set_thread_id(kInvalidThreadId);
{
FrameworkThreadTlsData *tls = GetTlsData();
if (tls != NULL)
{ }
//DCHECK(tls->managed == 0); // you must call ThreadManager::UnregisterThread before come there
}
FreeTlsData();
}
void FrameworkThread::InitTlsData(FrameworkThread *self)
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls == NULL);
if (tls != NULL)
return;
tls = new FrameworkThreadTlsData;
tls->self = self;
tls->managed = 0;
tls->managed_thread_id = -1;
tls->quit_properly = false;
tls->custom_data = NULL;
lazy_tls_data.Pointer()->Set(tls);
}
void FrameworkThread::FreeTlsData()
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return;
lazy_tls_data.Pointer()->Set(NULL);
delete tls;
}
FrameworkThreadTlsData* FrameworkThread::GetTlsData()
{
return lazy_tls_data.Pointer()->Get();
}
bool FrameworkThread::GetThreadWasQuitProperly()
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return false;
return tls->quit_properly;
}
void FrameworkThread::SetThreadWasQuitProperly(bool flag)
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return;
tls->quit_properly = flag;
}
FrameworkThread* FrameworkThread::current()
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return NULL;
return tls->self;
}
int FrameworkThread::GetManagedThreadId()
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return -1;
return tls->managed_thread_id;
}
void* FrameworkThread::GetCustomTlsData()
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return NULL;
return tls->custom_data;
}
void FrameworkThread::SetCustomTlsData(void *data)
{
FrameworkThreadTlsData *tls = GetTlsData();
//DCHECK(tls != NULL);
if (tls == NULL)
return;
tls->custom_data = data;
}
} // namespace nbase