Multiple threads
-
On 26/05/2014 at 04:04, xxxxxxxx wrote:
Thanks. I see it is a very basic example.
Some questions, I hope you can help me.I want to define 2 threads each processing half of the data.
How to pass on data to the threads.
Should I use global data, or can I parameters?
So instead of virtual void Main(void)for example virtual void Main(dataArray& myBaseArray)The documentation tells "MP threads should test for
TestBreak()
[URL-REMOVED]". But it seems that is only for BaseDraw. How to test for a keyboard Escape for example?Sorry for these beginner questions. I hope you can help me.
I will start with this basic example and see how far I get.-Pim
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 26/05/2014 at 15:13, xxxxxxxx wrote:
Pass the data to the constructor of your thread. Make sure its properly synchronized.
You can only check for keyboard Escape from the main thread. If you have a dialog open,
use it to either let the user press a button or check for the keyboard Escape there.Starting both threads asynchronously should work fine. In case your test already includes
a synchronization mechanism, make sure its locked/unlocked properly (eg. one mistake could
be that the lock is locked the for full execution time of the thread).I think that notice about MP threads is wrong, unless you get the BaseThread pointer from
some other place. Afaik, BaseThread::TestBreak() will simply call C4DThread::TestDBreak().Best,
-Niklas -
On 26/05/2014 at 16:27, xxxxxxxx wrote:
I use a 'control' thread based on Thread and that starts the mp threads. You should probably use data structures passed to your mp threads to pass information to each thread. My Greebler plugin uses threads to greeble polygonal objects by dividing the polygons up between threads. In my case, the processes are isolated so as to avoid the need for semaphore locking/unlocking required for synchronization. I will see if I have any 'example' code or can cobble together something like that for you when I have time.
-
On 27/05/2014 at 02:11, xxxxxxxx wrote:
Originally posted by xxxxxxxx
I will see if I have any 'example' code or can cobble together something like that for you when I have time.
Yes please, that would be very helpful.
-Pim
-
On 27/05/2014 at 05:20, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Afaik, BaseThread::TestBreak() will simply call C4DThread::TestDBreak().
Yep.
-
On 28/05/2014 at 12:01, xxxxxxxx wrote:
I managed to get the example working and also put everything in another thread.
So, cinema 4d responds when the threads are running.But how to respond to an esc, how to stop all threads?
I am using in my main thread ct.End(), but that does not stop the threads.
I think I need to use C4DThread::TestDBreak(), but where to put it. If I put it in the control thread, it is started initially and only once.Here some code
class ControlThread : public C4DThread { public: virtual void Main(void); virtual const Char* GetThreadName(void) { return "SDK ControlThread"; } virtual Bool TestDBreak(void); }; Bool ControlThread::TestDBreak(void) { GePrint("ControlThread::TestDBreak."); return true; } ... void MyThread::Main() { //ct.Start(THREADMODE_SYNCHRONOUS); // multiprocessing test ct.Start(THREADMODE_ASYNC); return; } Bool MyThread::KillThread() { GePrint ("MyThread::KillThread ct.End()"); ct.End(); return true; }
-
On 28/05/2014 at 17:25, xxxxxxxx wrote:
You need to test for a user ESC break in TestDBreak() (manually with GetInputEvent()?). I don't know anymore as I haven't tested for them in my MP threads for some time. And on a positive condition, you then End() your threads.
Using a base thread (now BaseThread with C4DThreads) :
// Thread.Main // - This is the Multi-Processor Control Thread //*---------------------------------------------------------------------------* void ControlThread::Main() //*---------------------------------------------------------------------------* { if (!mp.Start(THREADPRIORITY_NORMAL)) return; mp.Wait(); } // ControlThread.Initialize //*---------------------------------------------------------------------------* Bool ControlThread::Initialize() //*---------------------------------------------------------------------------* { BaseDocument::Free(doc); AtomArray::Free(marray); AtomArray::Free(aarray); // Greebler instance holding stock and custom objects Greebler* greebler = GetGreeblerData(); if (!greebler) return ErrPrt("ControlThread.Initialize.greebler"); // Get this once and for task-separation purposes cpu_count = GeGetCPUCount(); for (LONG i = 0L; i != cpu_count; ++i) { tlist[i] = &thread[i]; thread[i].Initialize(this, greebler->GetStockArray()); } // Initialize MPThread for later use if (!mp.Init(*this,cpu_count,tlist)) return ErrPrt("ControlThread.Initialize.mp.Init()"); // For combining results aarray = AtomArray::Alloc(); if (!aarray) return ErrPrt("ControlThread.Initialize.aarray"); marray = AtomArray::Alloc(); if (!marray) return ErrPrt("ControlThread.Initialize.marray"); doc = BaseDocument::Alloc(); if (!doc) return ErrPrt("ControlThread.Initialize.doc"); top = BaseObject::Alloc(Onull); if (!top) return ErrPrt("ControlThread.Initialize.top"); doc->InsertObject(top, NULL, NULL, FALSE); mcd.doc = doc; mcd.op = top; return TRUE; }
-
On 29/05/2014 at 04:58, xxxxxxxx wrote:
Sorry, TestDBreak seems to be triggered only once before the MP threads start.
It is not triggered when the MP threads are running.
It does not matter if I put it in the control thread or the MP thread?Small update:
If I put TestDBreak in the MP thread (like below) it is never triggered.
If I put TestDBreak in the control thread it is triggered only once.// example code for a menu plugin and multiprocessing #include "c4d.h" #include "c4d_symbols.h" #include "c4d_memory_mp.h" #define ID_PIM 123112 //test plugin id Bool escape_pressed() { BaseContainer bc; Bool rs = GetInputState(BFM_INPUT_KEYBOARD, KEY_ESC, bc); if (rs && bc.GetInt32(BFM_INPUT_VALUE)) { MessageDialog("Stopped by user."); GePrint("Stopped by user."); return true; } return false; } // end escape_pressed class MPTest : public C4DThread { public: Random rnd; Int32 start; Float result; Float duration; virtual void Main(void); virtual const Char* GetThreadName(void) { return "SDK MpTest"; } virtual Bool TestDBreak(void); }; Bool MPTest::TestDBreak(void) { GePrint("MPTest::TestDBreak: esc? " + escape_pressed()); return true; } void MPTest::Main(void) { // ... See example } class ControlThread : public C4DThread { public: virtual void Main(void); virtual const Char* GetThreadName(void) { return "SDK ControlThread"; } //virtual Bool TestDBreak(void); }; //Bool ControlThread::TestDBreak(void) //{ // GePrint("ControlThread::TestDBreak: esc? " + escape_pressed()); // return true; //} void ControlThread::Main(void) { GeShowMouse(MOUSE_BUSY); MPThreadPool mp; Int32 i, cnt = GeGetCPUCount(); GePrint("Nr of processors / cores: " + String::IntToString(cnt)); if (cnt == 0) return; MPAlloc<MPTest> thread; AutoGeFree<C4DThread*> list = NewMemClear(C4DThread *, cnt); if (!list || !thread.Init(cnt)) return; for (i = 0; i < cnt; i++) { thread[i].start = i; thread[i].result = 0.0; list[i] = &thread[i]; } if (!mp.Init(*this, cnt, list)) return; Float64 start_time = GeGetMilliSeconds(); if (!mp.Start(THREADPRIORITY_BELOW)) return; Float64 start_duration = GeGetMilliSeconds() - start_time; mp.Wait(); //... set string See example GeShowMouse(MOUSE_NORMAL); MessageDialog(str); } class MenuTest : public CommandData { public: virtual Bool Execute(BaseDocument* doc); }; Bool MenuTest::Execute(BaseDocument* doc) { ControlThread ct; return ct.Start(THREADMODE_SYNCHRONOUS); // multiprocessing test } Bool RegisterMyPlugin(void) { // ... }
-
On 31/05/2014 at 07:39, xxxxxxxx wrote:
I tried various ways, but still I do not know how to stop the multi threads or where to put TestDBreak.
I'm getting no response no matter where I put mp.End()? -
On 03/06/2014 at 02:19, xxxxxxxx wrote:
I'm starting to pull my hair out of my head.
Still can't get it to work.All help is appreciated!
-
On 03/06/2014 at 05:42, xxxxxxxx wrote:
Ok, I solves it using a workaround (as in ScottA's example).
Still doubt about .End(), but this workaround works for me.-Pim