📄 threadsubobj.cpp
字号:
/*--------------------------------------------------------------------------*
* File Name: ThreadSubObj.cpp *
* Purpose: Demostrate realtime update on a graph *
* Creation: April 04, 2000 *
* Copyright (c) 2000 Microcal Software, Inc. *
* *
* Modification Log: *
*--------------------------------------------------------------------------*/
#include "ThreadSubObj.h"
int random_int(int iMin, int iMax);
static UINT GenericThreadRun(LPVOID lpParam);
//---------------------------------------------------------------------------
// Property Map:
//
// The Property Map is for declaring the properties of your LabTalk object.
//
// A property is mapped to Get and Set function. These functions allow
// you to do error checking or any necessary conversions. A read-only
// property can be declared by using the _GET macro.
//
// MOCA_PROP_INT( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_REAL( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_STR( <GetFunction>,<SetFunction>,<PropertyNameStr> )
// MOCA_PROP_INT_GET( <GetFunction>,<PropertyNameStr> )
// MOCA_PROP_REAL_GET( <GetFunction>,<PropertyNameStr> )
// MOCA_PROP_STR_GET( <GetFunction>,<PropertyNameStr> )
//
// A Simple Property is mapped to a data member. There are no Get/Set
// functions for a Simple Property. MOCA will take care of the assignment.
// A simple read-only property can be declared by using the _GET macro.
//
// MOCA_SIMPLE_PROP_INT( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_REAL( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_STR( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_INT_GET( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_REAL_GET( <DataMember>,<PropertyNameStr> )
// MOCA_SIMPLE_PROP_STR_GET( <DataMember>,<PropertyNameStr> )
//---------------------------------------------------------------------------
MOCA_BEGIN_PROP_MAP(CThreadSubObj, CMOCAObjBase)
MOCA_PROP_INT(GetPriority, SetPriority, "Priority")
MOCA_SIMPLE_PROP_INT_GET(m_iStatus, "Status")
MOCA_PROP_STR_GET(GetStatusStr, "StatusDescrip")
MOCA_END_PROP_MAP(CThreadSubObj, CMOCAObjBase)
//---------------------------------------------------------------------------
// Method Map:
//
// INPORTANT: To have a Method Map or a SubObject Map, you must
// have a property map.
//
// MOCA_METHOD( <MemberFunction>,<MethodNameStr> )
//
// <MemberFunction> must be declared as "BOOL foo(double &, CStringArray &);"
// The double is used for storing LabTalk's return value.
// The CStringArray contains the arguments passed from LabTalk.
//---------------------------------------------------------------------------
MOCA_BEGIN_METH_MAP(CThreadSubObj, CMOCAObjBase)
MOCA_METH_ENTRY(Meth_Start, "Start")
MOCA_METH_ENTRY(Meth_Suspend, "Suspend")
MOCA_METH_ENTRY(Meth_Resume, "Resume")
MOCA_METH_ENTRY(Meth_Kill, "Kill")
MOCA_END_METH_MAP(CThreadSubObj, CMOCAObjBase)
//---------------------------------------------------------------------------
CThreadSubObj::CThreadSubObj()
{
m_iNumPoints = 150; // obj.NumPoints
m_iPriority = DOTHREAD_PRIORITY_NORMAL; // obj.Thread.Priority
m_iStatus = DOTHREAD_STATUS_NOT_PRESENT; // obj.Thread.Status
m_pThread = NULL;
m_bKill = FALSE;
}
CThreadSubObj::~CThreadSubObj()
{
}
//---------------------------------------------------------------------------
BOOL CThreadSubObj::GetPriority(int &iValue)
{
iValue = m_iPriority;
return TRUE;
}
BOOL CThreadSubObj::SetPriority(int iValue)
{
if( iValue >= 0 && iValue <= DOTHREAD_PRIORITY_MAXIMUM )
{
m_iPriority = iValue;
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::GetStatusStr
//
//---------------------------------------------------------------------------
BOOL CThreadSubObj::GetStatusStr(LPSTR lpstr)
{
switch( m_iStatus )
{
case DOTHREAD_STATUS_RUNNING:
lstrcpy(lpstr, "Running");
break;
case DOTHREAD_STATUS_SUSPENDED:
lstrcpy(lpstr, "Suspended");
break;
case DOTHREAD_STATUS_NOT_PRESENT:
lstrcpy(lpstr, "Not Present");
break;
default:
lstrcpy(lpstr, "Unknown");
break;
}
return TRUE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::Meth_Start
//
// LabTalk will return 1 on success and 0 on failure.
//---------------------------------------------------------------------------
BOOL CThreadSubObj::Meth_Start(double &dValue, CStringArray &strArgArray)
{
if( strArgArray.GetSize() == 0 ) // method expects no arguments
{
if( IS_THREAD_STARTED(m_iStatus) )
{
dValue = 1.0; // already started, return success to LabTalk
}
else
{
static const int l_nPriority[] =
{
THREAD_PRIORITY_IDLE,
THREAD_PRIORITY_LOWEST,
THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_NORMAL,
THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_HIGHEST, // computer might freeze with this priority
THREAD_PRIORITY_TIME_CRITICAL, // computer might freeze with this priority
};
ASSERT(NULL == m_pThread);
ASSERT(sizeof(l_nPriority)/sizeof(l_nPriority[0]) == DOTHREAD_PRIORITY_MAXIMUM + 1);
// Convert LabTalk priority value to Windows API priority value
int iPriority = l_nPriority[m_iPriority];
// We are passing the pointer to the method object
// as lpParam, so that we can use it inside 'GenericThreadRun'.
m_pThread = AfxBeginThread(GenericThreadRun, this, iPriority, 0);
if( m_pThread )
{
m_iStatus = DOTHREAD_STATUS_RUNNING;
dValue = 1.0;
}
else
dValue = 0.0;
}
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::Meth_Kill
//
// LabTalk will return 1 on success and 0 on failure.
//---------------------------------------------------------------------------
BOOL CThreadSubObj::Meth_Kill(double &dValue, CStringArray &strArgArray)
{
if( strArgArray.GetSize() == 0 ) // method expects no arguments
{
if( IS_THREAD_STARTED(m_iStatus) )
{
ASSERT_VALID(m_pThread);
// If the thread is not suspended then suspend it
if( !IS_THREAD_SUSPENDED(m_iStatus) )
VERIFY(0 == m_pThread->SuspendThread());
// We do not set 'm_iStatus' here. It will be set by the thread.
// Here we simply set the Kill flag.
m_bKill = TRUE;
// Resume thread and allow it to end gracefully
VERIFY(1 == m_pThread->ResumeThread());
}
dValue = 1.0; // return success to LabTalk
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::Meth_Suspend
//
// LabTalk will return 1 on success and 0 on failure.
//---------------------------------------------------------------------------
BOOL CThreadSubObj::Meth_Suspend(double &dValue, CStringArray &strArgArray)
{
if( strArgArray.GetSize() == 0 )
{
if( IS_THREAD_RUNNING(m_iStatus) )
{
ASSERT_VALID(m_pThread);
// Check the return value (must be 0 if the thread was running)
VERIFY(0 == m_pThread->SuspendThread());
// Update status property
m_iStatus = DOTHREAD_STATUS_SUSPENDED;
}
dValue = 1.0; // return success to LabTalk
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::Meth_Resume
//
// LabTalk will return 1 on success and 0 on failure.
//---------------------------------------------------------------------------
BOOL CThreadSubObj::Meth_Resume(double &dValue, CStringArray &strArgArray)
{
if( strArgArray.GetSize() == 0 )
{
if( IS_THREAD_SUSPENDED(m_iStatus) )
{
ASSERT_VALID(m_pThread);
DWORD dw = m_pThread->ResumeThread();
ASSERT(dw != 0); // should not happen here
// ResumeThread returns the follwing:
// 0 = thread was not suspended
// 1 = thread was suspended, but now restarted
// >1 = thread is still suspended
// 0xFFFFFFFF = failure
if( dw == 0xFFFFFFFF )
{
dValue = 0.0; // return failure to LabTalk
}
else
{
dValue = 1.0; // return success to LabTalk
if( dw == 1 )
m_iStatus = DOTHREAD_STATUS_RUNNING;
}
}
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// CThreadSubObj::Run
//
// This is where the thread spends most of it's time.
//---------------------------------------------------------------------------
UINT CThreadSubObj::Run()
{
ASSERT_VALID(m_pThread);
MOINDEX ii;
double dd;
BOOL bDone = FALSE;
// Get number of points to update
int iNumPoints = m_iNumPoints;
// Update status property
m_iStatus = DOTHREAD_STATUS_RUNNING;
MoResultData dataY(m_strWksName, 2); // second column
if( !dataY.IsValid() )
goto finish_thread;
// Make sure redraw is done in real time:
dataY.set_redraw_mode(MoData::REALTIME_ON_IDLE | MoData::REDRAW_REALTIME);
// Modata.iRange2 is the actual range already in wks
// Modata.i2 is the active/selected range that math calculation should use
// Loop forever (the thread will be killed from outside)
do
{
MOINDEX FirstRow = dataY.i2();
MOINDEX LastRow = FirstRow + iNumPoints;
for( ii = FirstRow; ii <= LastRow; ii++ )
{
/// we only do SetValue if within range as otherwise
/// SetValue will attemp to expand the COKData memory which is
/// not recommended
if( ii + 1 >= m_iMaxNumPoints)
{
m_bKill = TRUE;
break;
}
// The following if/else is used to create some random data
// based on the existing data. In a "real" DLL this data would
// come from another source such as a data aquisition board.
dd = 0.0;
if( random_int(0,1) )
{
dd += random_int(0,20);
if( dd > 200 )
dd = 200;
}
else
{
dd -= random_int(0,20);
if( dd < 0 )
dd = 0;
}
// Put the data into the Y column.
dataY.SetValue(ii, dd);
}
// Force idle update
dataY.UpdateRange();
Sleep(500); // 500 miliseconds
// Check if user wants to kill the thread
if ( m_bKill )
{
bDone = TRUE;
break;
}
} while( !bDone );
finish_thread:
// Clear the Kill flag.
m_bKill = FALSE;
// We do not delete the thread here. MFC will delete it when it exits.
m_pThread = NULL;
// Update status property.
m_iStatus = DOTHREAD_STATUS_NOT_PRESENT;
return 0;
}
//---------------------------------------------------------------------------
// GenericThreadRun
//
// This is the entry point into the running action of the thread.
// The thread will terminate either when this function returns
// or when it is killed from outside.
//---------------------------------------------------------------------------
static UINT GenericThreadRun(LPVOID lpParam)
{
CThreadSubObj *pDoThread = (CThreadSubObj*)lpParam;
return pDoThread->Run();
}
//---------------------------------------------------------------------------
// random_int
//
//---------------------------------------------------------------------------
int random_int(int iMin, int iMax)
{
int i = iMax - iMin + 1;
double d;
d = (double)RAND_MAX / (double)i;
d = (double)rand() / d;
return (iMin + (int)d);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -