自定義腳本語言引擎開發紀實 - 實例化C++實現類的對象和調用對象的方法

線程安全性

由於解釋器並沒有提供線程的調度功能,而是藉助宿主語言使用系統機制。而解釋器從一開始實現並不是線程安全,所以,所以呢?給線程的執行加了一個限制:線程函數除了可以訪問當前thread對象的數據外,不能訪問引擎當前變量池中的其他變量。

線程的邏輯,要保存到一個文件裏,有一個新的解析器對象去執行。與主線程中的解析器是隔離開的,做到互補干擾。缺點也一目瞭然:需要訪問的已有的全局變量,訪問不到。要想訪問:重新賦值,或者把數據塞給thread對象。

c++類

//thread.h
#pragma once

#include "varobject.h"

/**
	腳本內部的變量存取,都是非線程安全的
*/

class CScript;
namespace os
{
	class thread : public varobject
	{
	public:
		//在腳本中展現的類名
		static const char* get_script_classname() {return "thread";}

		typedef struct st_thread_startup 
		{
			HANDLE hEvent;
			thread* pThread;
			CStringA toRunFile;
		}*lp_st_thread_startup;

		thread(std::tr1::shared_ptr<_variant_>* pParams, DWORD dwParams);
		~thread();

		int QueryMethod(LPCSTR lpszMethodName);
		BOOL CallMethod(int nMethodId, std::tr1::shared_ptr<_variant_>* pParams, DWORD dwParamN, std::tr1::shared_ptr<_variant_>& varR, std::tr1::shared_ptr<_variant_>* arrVarValue, DWORD dwCount);

	protected:
		unsigned start(const char* torunfile, unsigned stacksize, unsigned initflag);


	protected:
		static unsigned __stdcall thread_proc(void* lp);
		std::tr1::shared_ptr<CScript> m_script;
	};
}
//thead.cpp
#include "stdafx.h"
#include "thread.h"
#include "script.h"
#include "scriptinc.h"

namespace os
{
	#define THREAD_METHOD_START		1
	#define THREAD_METHOD_PAUSE		2
	#define THREAD_METHOD_RESUME	3
	#define THREAD_METHOD_STOP		4
	#define THREAD_METHOD_WAIT		5
	#define THREAD_METHOD_KILL		6

	#define VARIANT_ID_NAME			"id"
	#define VARIANT_HANDLE_NAME		"handle"

	thread::thread(std::tr1::shared_ptr<_variant_>* pParams, DWORD dwParams)
	{
		append(VARIANT_ID_NAME, std::tr1::shared_ptr<_variant_>(new (std::nothrow)_variant_(0)));
		append(VARIANT_HANDLE_NAME, std::tr1::shared_ptr<_variant_>(new (std::nothrow)_variant_(0)));
		m_script.reset(new (std::nothrow) CScript());
	}

	thread::~thread()
	{
		m_script.reset();
	}

	int thread::QueryMethod(LPCSTR lpszMethodName)
	{
		if(_stricmp(lpszMethodName, "start") == 0)
			return THREAD_METHOD_START;
		if(_stricmp(lpszMethodName, "pause") == 0)
			return THREAD_METHOD_PAUSE;
		if(_stricmp(lpszMethodName, "resume") == 0)
			return THREAD_METHOD_RESUME;
		if(_stricmp(lpszMethodName, "wait") == 0)
			return THREAD_METHOD_WAIT;
		if(_stricmp(lpszMethodName, "kill") == 0)
			return THREAD_METHOD_KILL;
		
		return 0;
	}

	BOOL thread::CallMethod(int nMethodId, std::tr1::shared_ptr<_variant_>* pParams, DWORD dwParamN, std::tr1::shared_ptr<_variant_>& varR, std::tr1::shared_ptr<_variant_>* arrVarValue, DWORD dwCount)
	{
		BOOL lr = TRUE;
		if(nMethodId == THREAD_METHOD_START)
		{
			unsigned id = 0;
			
			if(dwParamN >= 1)
			{
				unsigned stack_size = 0;
				unsigned initflag = 0;
				if(dwParamN >= 2)
					stack_size = (*(pParams + 1))->asUInt64();
				if(dwParamN >= 3)
					initflag = (*(pParams + 2))->asUInt64();

				unsigned id = start((*pParams)->asCString(), stack_size, initflag);
			}

			varR.reset(new (std::nothrow) _variant_(id));
		}
		else if(nMethodId == THREAD_METHOD_PAUSE)
		{
#ifdef _DEBUG
			CStringA strLog;
			strLog.Format("[script][thread][pause] 警告警告:掛起線程時,如果線程正在分配堆中的內存,線程將鎖定堆;腳本的臨時變量會new申請堆,造成卡死,不建議調用");
			OutputDebugStringA(strLog);
			ATLASSERT(FALSE);
#endif
			DWORD dwRet = 0;
			const std::tr1::shared_ptr<_variant_>& varHandle = find(VARIANT_HANDLE_NAME);
			if(varHandle && varHandle->is_ui8())
			{
				HANDLE handle = (HANDLE)varHandle->asUInt64();
				if(handle)
				{
					dwRet = ::SuspendThread(handle);
				}
			}

			varR.reset(new (std::nothrow) _variant_(dwRet));
		}
		else if(nMethodId == THREAD_METHOD_RESUME)
		{
			DWORD dwRet = 0;
			const std::tr1::shared_ptr<_variant_>& varHandle = find(VARIANT_HANDLE_NAME);
			if(varHandle && varHandle->is_ui8())
			{
				HANDLE handle = (HANDLE)varHandle->asUInt64();
				if(handle)
				{
					dwRet = ::ResumeThread(handle);
				}
			}

			varR.reset(new (std::nothrow) _variant_(dwRet));
		}
		else if(nMethodId == THREAD_METHOD_WAIT)
		{
			DWORD ret = -1;
			const std::tr1::shared_ptr<_variant_>& varHandle = find(VARIANT_HANDLE_NAME);
			if(varHandle && varHandle->is_ui8())
			{
				HANDLE handle = (HANDLE)varHandle->asUInt64();
				if(handle)
				{
					DWORD dwWait = 0;
					if(dwParamN > 0)
						dwWait = (*pParams)->asUInt64();
					
					ret = ::WaitForSingleObject(handle, dwWait);
				}
			}
			varR.reset(new (std::nothrow) _variant_(ret));
		}
		else if(nMethodId == THREAD_METHOD_KILL)
		{
			BOOL ret = FALSE;
			const std::tr1::shared_ptr<_variant_>& varHandle = find(VARIANT_HANDLE_NAME);
			if(varHandle && varHandle->is_ui8())
			{
				HANDLE handle = (HANDLE)varHandle->asUInt64();
				if(handle)
				{
#ifdef _DEBUG
					CStringA strLog;
					strLog.Format("[script][thread][kill] 警告警告:TerminateThread 不建議調用");
					OutputDebugStringA(strLog);
					ATLASSERT(FALSE);
#endif
					DWORD exitcode = 0;
					if(dwParamN >= 1)
						exitcode = (*pParams)->asUInt64();

					ret = ::TerminateThread(handle, exitcode);
				}
			}

			varR.reset(new (std::nothrow) _variant_(ret));
		}
		else
			lr = FALSE;
		return lr;
	}

	unsigned thread::start(const char* torunfile, unsigned stacksize, unsigned initflag)
	{
		ATLASSERT(torunfile != NULL && strlen(torunfile) > 0);
		unsigned id = 0;
		st_thread_startup startup;
		startup.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
		if(startup.hEvent != NULL)
		{
			startup.pThread = this;
			startup.toRunFile = torunfile;
			uintptr_t handle = _beginthreadex(NULL, stacksize, thread_proc, &startup, initflag, &id);
			if(handle > 0)
			{
				::WaitForSingleObject(startup.hEvent, INFINITE);
				::CloseHandle(startup.hEvent);
				modify(VARIANT_ID_NAME, std::tr1::shared_ptr<_variant_>(new (std::nothrow)_variant_(id)));
				modify(VARIANT_HANDLE_NAME, std::tr1::shared_ptr<_variant_>(new (std::nothrow)_variant_(handle)));
			}
		}
		return id;
	}

	unsigned __stdcall thread::thread_proc(void* lp)
	{
		st_thread_startup* pstartup = reinterpret_cast<st_thread_startup*>(lp);
		if(pstartup)
		{
			thread* pThis = pstartup->pThread;
			if(pThis)
			{
				CStringA toRunFile = pstartup->toRunFile;
#ifdef ENABLE_SCRIPT_DEBUGINFO_OUTPUT
				CStringA strLog;
				strLog.Format("[script][thread_proc] torunfile:%s", toRunFile);
#endif
				if(pstartup->hEvent)
				{
					::SetEvent(pstartup->hEvent);
				}

				if(pThis->m_script)
				{
					//下面執行具體的線程邏輯
					//在一個全新的script對象裏運行線程的函數
					if(::PathFileExistsA(toRunFile))
					{
						pThis->m_script->ExecuteFromFile(toRunFile);
					}
				}
			}
		}
		return 0;
	}
}

腳本中實例化這個c++類

//實例化C++類
_thread = thread()

給類的實例添加一下數據

_thread.ext="text"
_thread.sum=10

完成的腳本例子

//mm.script, 腳本函數
for(i=0,i<100000,1)
	js.debug.p("i")
end
_thread = thread()
_thread.ext="text"
_thread.sum=10
_thread.start("C:\\Users\\Administrator\\Desktop\\pack_236\\mm.script")
_thread.wait(2000)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章