自定义脚本语言引擎开发纪实 - 实例化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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章