ObjectARX多线程 Create Thread in ObjectARX

作者: admin 分类: C++,CAD,ObjectARX 发布时间: 2021-10-07 19:53

Create Thread in ObjectARX

Dear all,

I am trying to create a thread in an ObjectARX project. The function I used is
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunc, NULL, 0, &dwThreadId).

After the creation, the thread ID and Handle are returned successfully. But the created thread has never run.

Can anyone tell me if there is any way to solve this problem?

Cheers,

Yang

Report

0 Likes

REPLY

6 REPLIES

MESSAGE 2 OF 7

说明: *Owen Wengerd

 

*Owen Wengerd

 

in reply to: zhengy

07-26-2006 02:10 PM

 

Yang:

> After the creation, the thread ID and Handle are returned successfully.
> But the created thread has never run.

How are you determining that the thread hasn't executed? Are you trying
to create the thread from within your DllMain() function?

Owen Wengerd
President, ManuSoft ==> http://www.manusoft.com
VP Americas, CADLock, Inc. ==> http://www.cadlock.com

Report

0 Likes

REPLY

MESSAGE 3 OF 7

说明: zhengy

 

zhengy

 

in reply to: zhengy

07-27-2006 03:05 AM

 

Hi Owen,

Thanks for your kindly reply. I attached the snippet of my
code. I have registered a command "watch" in the command stack to activate the watchDb() method.

After the CreateThread () method, I got a returned value for the thread ID and the handle.

However, nothing is printed out like the first operation (print the sentence ("Already in Thread")), which makes me believe that the thread is not run.

I also use a software (like Windows Task Manager) that is able to trace all the Processes and their Threads, but the ThreadFun thread is not in the list.

void watchDb ()
{
if (gpDbr == NULL) {
gpDbr = new AsdkDbReactor();
}

acdbHostApplicationServices()->workingDatabase()->addReactor(gpDbr);

DWORD dwThreadId=0;
if (CreateThread(NULL,
0, (LPTHREAD_START_ROUTINE)ThreadFunc, NULL,
0, &dwThreadId) == NULL)
{
acutPrintf("NULL Thread\n");
return ;
}
acutPrintf("\nThread id = %d\n", dwThreadId);
}

void ThreadFunc () {
acutPrintf("Already in Thread\n");

}

Thanks a lot.

Yang

Report

0 Likes

REPLY

MESSAGE 4 OF 7

说明: OysteinW

 

说明: Advocate OysteinW

 

in reply to: zhengy

07-27-2006 03:57 AM

 

From objectARX doc:

"ObjectARX Does Not Support Multi-Threaded Programming
If you spawn multiple threads in your application, make sure that no more than one of the threads at a time invokes anything in the ObjectARX system."

Report

1 Like

REPLY

MESSAGE 5 OF 7

说明: *J. Daniel Smith

 

*J. Daniel Smith

 

in reply to: zhengy

07-27-2006 06:33 AM

 

From the MSDN docs for CreateThread(): "A thread in an executable that calls
the C run-time library (CRT) should use the _beginthread and _endthread
functions for thread management…".

Dan

wrote in message news:5250034@discussion.autodesk.com…
Hi Owen,

Thanks for your kindly reply. I attached the snippet of my
code. I have registered a command "watch" in the command stack to activate
the watchDb() method.

After the CreateThread () method, I got a returned value for the thread ID
and the handle.

However, nothing is printed out like the first operation (print the sentence
("Already in Thread")), which makes me believe that the thread is not run.

I also use a software (like Windows Task Manager) that is able to trace all
the Processes and their Threads, but the ThreadFun thread is not in the
list.

void watchDb ()
{
if (gpDbr == NULL) {
gpDbr = new AsdkDbReactor();
}

acdbHostApplicationServices()->workingDatabase()->addReactor(gpDbr);

DWORD dwThreadId=0;
if (CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunc, NULL,
0, &dwThreadId) == NULL)
{
acutPrintf("NULL Thread\n");
return ;
}
acutPrintf("\nThread id = %d\n", dwThreadId);
}

void ThreadFunc () {
acutPrintf("Already in Thread\n");

}

Thanks a lot.

Yang

Report

0 Likes

REPLY

MESSAGE 6 OF 7

说明: *Owen Wengerd

 

*Owen Wengerd

 

in reply to: zhengy

07-27-2006 07:39 AM

 

Your acutPrintf() call is not a reliable way to check whether the thread
is executing, because ObjectARX API functions do not support asynchronous
reentrancy. Use something independent of AutoCAD (such OutputDebugString
under a debugger) to test whether your thread is executing. 说明: :slightly_smiling_face:

Owen Wengerd
President, ManuSoft ==> http://www.manusoft.com
VP Americas, CADLock, Inc. ==> http://www.cadlock.com

Report

0 Likes

REPLY

MESSAGE 7 OF 7

说明: zhengy

 

zhengy

 

in reply to: zhengy

‎07-27-2006 11:12 PM

 

Yes, Owen, you are definitely right. I tried other approaches and found out that the created thread was running, but it could not print out anything on the AutoCAD screen using acutPrintf().

Thanks for all the replies to help me out.

Cheers,

Yang Message was edited by: zhengy

Report

0 Likes

REPLY

 

How to use threads in ObjectARX?

By Adam Nagy

How do I call an AutoCAD command from a background thread? When I try to call AcApDocManager::sendStringToExecute(), it causes AutoCAD to terminate unexpectedly.

Solution

The AutoCAD API functions are not thread safe – i.e. they do not expect to be called from a thread other than the main one.

You can create your own threads for background processing, but if you need to call an ARX function (even just to execute an AutoCAD command), then you need to marshal that call to the main thread.

We have a DevNote on this topic concerning .NET AddIns called "Use Thread for background processing", and you can handle this situation in ARX in a similar fashion.

You could write a helper class that creates a message only window, that could be used to invoke AutoCAD functions on the main thread.

class MyInvoker

{

public:

  MyInvoker()

  {

    WNDCLASS wndclass = {0};

    wndclass.hInstance     = _hdllInstance ;

    wndclass.lpfnWndProc   = wndProcedure;

    wndclass.lpszClassName = L"MessageOnlyWindow";

 

    // Register the class

    ATOM a = RegisterClass(&wndclass);

 

    // Create the window object

    _hwnd = CreateWindow(L"MessageOnlyWindow",

      NULL,

      NULL,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      NULL,

      NULL,

      _hdllInstance,

      NULL);

  }

 

  ~MyInvoker()

  {

    DestroyWindow(_hwnd);

  }

 

  typedef void (*CallbackFunctionType)();

  void InvokeSync(CallbackFunctionType funcPtr)

  {

    SendMessage(_hwnd, _wm, 0, (LPARAM)funcPtr);

  }

 

private:

  HWND _hwnd;

  static DWORD _wm;

  static LRESULT CALLBACK wndProcedure(

    HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

  {

    if (Msg == _wm)

    {

      CallbackFunctionType funcPtr = (CallbackFunctionType)lParam;

      (*funcPtr)();

    }

 

    return DefWindowProc(hWnd, Msg, wParam, lParam);

  }

};

DWORD MyInvoker::_wm = RegisterWindowMessage(L"MyInvokeMessage");

// a global instance of the helper class

MyInvoker * g_myInvoker;

Create an instance of this class in the kInitAppMsg

virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt)

{

  // TODO: Load dependencies here

 

  // You *must* call On_kInitAppMsg here

  AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg(pkt);

 

  // TODO: Add your initialization code here

  g_myInvoker = new MyInvoker();

 

  return (retCode) ;

}

And delete it in the kUnloadAppMsg

virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt)

{

  // TODO: Add your code here

 

  // You *must* call On_kUnloadAppMsg here

  AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg(pkt);

 

  // TODO: Unload dependencies here

  delete g_myInvoker;

 

  return (retCode) ;

}

You would need to place the ARX calls into a seperate function that then could be invoked on the main thread. Note that now we are in session/application context so if you wanted to modify the database you would need to lock the document

void acadFunctionCalls()

{

  AcApDocument * activeDoc = acDocManager->mdiActiveDocument();   

 

  acDocManager->sendStringToExecute(

    activeDoc,

    L"\x03\x03(command \"LINE\" \"0,0\" \"100,100\" \"\") "); 

}

Here is the function that the background thread will execute

UINT thread( LPVOID pParam )

{

  // we are doing some calculations in the thread

  Sleep(3000);

 

  // now we want to call some AutoCAD functions

  g_myInvoker->InvokeSync(acadFunctionCalls);

 

  return (0);  //exit from thread       

}

And here is the AutoCAD command that will start the background thread

static void MfcThreadTest_StartThread(void)

{

  AfxBeginThread(thread,NULL,THREAD_PRIORITY_LOWEST);

}

Posted at 07:11 AM in Adam NagyAutoCADObjectARX | Permalink

 

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

标签云