doc_and_tools/tools/sdk/include/threads/thread.h

225 lines
6.9 KiB
C++

// thread.h : the base utility for thread pool management
//
// Author: Gongbing
//
// Create: 2017-05-20
#pragma once
#ifndef _INCLUDED_REF_
#define _INCLUDED_REF_
#include "../ref/ref.h"
#endif
#pragma warning(disable: 4996)
////////////////////////////////////////////////////////////////////////////////////////////
// thread ...
//
// purpose: if you CreateThrad and TerminateThread then, the new thread maybe occupying the global
// RTL_CRITICAL_SECTION variable in ntdll.dll module. In this situation, all threads that
// created by CreateThread will no longer have opportunity to run!!!
// This class is providing you to TerminateThread safely
namespace thread_util
{
enum _io_direction
{
IO_WRITE = 1,
IO_READ,
IO_CONTROL,
IO_USER_TYPE_BASE = 10,
};
#pragma pack(push)
#pragma pack(1)
typedef struct _ovl_extension : OVERLAPPED
{
int io_direction; // _io_direction
size_t buf_len; // bytes of payload buffer
size_t data_len; // valid bytes of payload
size_t io_pos; // current IO position
char payload[8]; // payload data buffer
char* user_payload(void)
{
return payload;
}
}OVLEX, *LPOVLEX;
#pragma pack(pop)
__declspec(novtable) struct ILock : public ref_util::IRef
{
COM_API_DECLARE(void, lock(void));
COM_API_DECLARE(bool, try_lock(void));
COM_API_DECLARE(void, unlock(void));
};
__declspec(novtable) struct IThreadWorker : public ref_util::IRef
{
COM_API_DECLARE(void*/*void* tls*/, thread_enter(void)); // you can initialize tls in this method
COM_API_DECLARE(void, thread_work(void*/*bind data*/ task_key, LPOVLEX task_data, unsigned data_size, DWORD err_code, void* enter_data));
COM_API_DECLARE(void, thread_exit(void* enter_data/*tls*/));
};
__declspec(novtable) struct IThreadPool : public ref_util::IRef
{
COM_API_DECLARE(long, add_task(void* task_key, void* task_data, unsigned data_size)); // return 0 when success
COM_API_DECLARE(long, stop(void));
COM_API_DECLARE(long, worker_threads(void));
COM_API_DECLARE(long, busy_threads(void));
COM_API_DECLARE(long, waiting_task(void));
};
__declspec(novtable) struct IEventDispatchThreadPool : public IThreadPool // dispach thread pool through by hardware-event mechanism
{
COM_API_DECLARE(long, bind_object(void* object, void* bind_key));
COM_API_DECLARE(long, remove_object(void* object, void* bind_key));
};
class simple_lock
{
ILock *lck_;
public:
simple_lock(ILock* lck)
{
lck_ = lck;
if (lck_)
{
//lck_->add_ref();
lck_->lock();
}
}
~simple_lock()
{
if (lck_)
{
lck_->unlock();
//lck_->release();
}
}
};
// for reducing the times of memory copying, request memory from inner - added on 2019-07-28
PORT_API(LPOVLEX) inner_buffer_to_OVLEX_head(void* buf/*'buf' is returned by request_inner_buffer*/);
PORT_API(char*) request_inner_buffer(size_t bytes);
PORT_API(void) free_inner_buffer(void* buf); // free the buffer returned by 'request_inner_buffer'
PORT_API(void) free_inner_buffer(LPOVLEX buf); // free the buffer returned by 'request_inner_buffer'
PORT_API(HANDLE) create_thread(unsigned(__stdcall* thread)(void*), void* param, bool suspend = false, unsigned allow_cpu_mask = -1); // return thread id
PORT_API(ILock*) create_lock(void);
PORT_API(IThreadPool*) create_thread_pool(IThreadWorker* worker, int desired_threads = 0, unsigned cpu_allow_mask = -1);
PORT_API(IEventDispatchThreadPool*) create_event_thread_pool(IThreadWorker* worker, int desired_threads = 0, unsigned cpu_allow_mask = -1);
// parameter of result:
// data: (wchar_t*)thread name, maybe null
// len: thread id
// total: start address
PORT_API(void) enum_threads(DWORD proc_id, inter_module_data::set_data result, void* param);
PORT_API(LPVOID) get_thread_start_address(DWORD thread_id);
PORT_API(DWORD) get_call_stack(DWORD ebp, DWORD *stack/*caller allocate the buffer*/, int depth = 6, void* ensure_module = NULL/*ensure the module which contains the address ensure_module in the stack, omit if stack_data was valid*/
, unsigned char* stack_data = NULL, int stack_bytes = 0); // return depth in stack
PORT_API(DWORD) get_thread_call_stack(DWORD thread_id, DWORD *stack/*caller allocate the buffer*/, int depth = 6, void* ensure_module = NULL/*ensure the module which contains the address ensure_module in the stack*/); // return depth in stack
PORT_API(void) set_thread_name(DWORD thread_id, const char* thread_name);
// the parameter 'allow_cpu_mask' is is a bit vector in which each bit represents the processors that a thread is allowed to run on
// 1 represent CPU0, 5 represent CPU0 and CPU2, and so on...
enum _ict_state
{
ICT_STATE_NONE = 0,
ICT_STATE_START_FAIL,
ICT_STATE_RUNNING,
ICT_STATE_COMPLETE,
};
template<class T> // NOTE: class T must derived from ref_util::IRef !!!
class invoke_class_thread : public ref_util::refer
{
void(__stdcall T::* handle_func)(void*);
void *param_; // dynamic parameter should free in handle_func !!!
T *obj_;
HANDLE wait_;
HANDLE thread_;
unsigned thread_id_;
unsigned affinity_mask_;
_ict_state state_;
unsigned start_tick_; // elapse milliseconds if state_ == ICT_STATE_COMPLETE, start time tick counts in others
public:
invoke_class_thread(T* obj, void(__stdcall T::* thread_func)(void*), void* param, unsigned allow_cpu_mask = -1) : state_(ICT_STATE_NONE), start_tick_(0)
{
if (obj) obj->add_ref();
obj_ = obj;
param_ = param;
handle_func = thread_func;
wait_ = CreateEvent(NULL, TRUE, FALSE, NULL);
thread_ = thread_util::create_thread(invoke_thread, this, false, allow_cpu_mask);
if (thread_ == NULL) state_ = ICT_STATE_START_FAIL;
else
{
thread_id_ = GetThreadId(thread_);
WaitForSingleObject(wait_, INFINITE);
}
CloseHandle(wait_);
wait_ = NULL;
}
protected:
~invoke_class_thread()
{
if (thread_) CloseHandle(thread_);
if (obj_) obj_->release();
}
private:
static unsigned WINAPI invoke_thread(void* lp)
{
invoke_class_thread *obj = (invoke_class_thread*)lp;
obj->add_ref();
obj->state_ = ICT_STATE_RUNNING;
obj->start_tick_ = GetTickCount();
SetEvent(obj->wait_);
(obj->obj_->*obj->handle_func)(obj->param_);
obj->state_ = ICT_STATE_COMPLETE;
obj->start_tick_ = GetTickCount() - obj->start_tick_;
obj->release();
return 0;
}
public:
unsigned thread_id(void)
{
return thread_id_;
}
HANDLE thread(bool take = false)
{
HANDLE h = thread_;
if (take)
thread_ = NULL;
return h;
}
enum _ict_state thread_state(void)
{
return state_;
}
unsigned start_tick_count(bool elapse = false)
{
return elapse && state_ != ICT_STATE_COMPLETE ? GetTickCount() - start_tick_ : start_tick_;
}
int terminate(int reason = 0)
{
HANDLE h = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id_);
int err = GetLastError();
if (h)
{
err = TerminateThread(h, reason) ? ERROR_SUCCESS : GetLastError();
CloseHandle(h);
}
return err;
}
};
}