Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Multiple threads

    SDK Help
    0
    14
    1.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 21/05/2014 at 03:26, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   R15 
      Platform:   Windows  ;   
      Language(s) :     C++  ;

      ---------
      I took ScottA's thread example and added a second thread to it.
      So, now I can start 2 threads and it looks good. Two progress counters.

      However, on my Windows 7 with an i5 processor using the task manager, I do not see that extra threads are used when starting the second thread.
      The first thread starts up 2 threads, but starting the 2nd, I do not see any significant increase of processor activity / threads.

      Can I see which cinema 4d thread using which processor thread?
      Do I need to do something extra, to enable cinema to use all threads?
      E.g. do I need to use "class MPThreadPool"?
      If so, is there an example I can learn from?

      Some notes how I added the second thread in ScottA's example.

      class MyDialog : public GeDialog
      {
          private:
              MyThread th;
              MyThread th2;	//second thread
        
      ...
        
      	    case standardBtn2:       //The (regular style) start thread button
                      th2.Start();
      ...
      

      -Pim

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 23/05/2014 at 02:17, xxxxxxxx wrote:

        I guess nobody used "class MPThreadPool" before?

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 23/05/2014 at 12:02, xxxxxxxx wrote:

          I don't know the referenced code you took your code from but an implementation example for multithreading is given in the sdk docs. Check out the MPThreadPool page.

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            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.

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                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.

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  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

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 27/05/2014 at 05:20, xxxxxxxx wrote:

                    Originally posted by xxxxxxxx

                    Afaik, BaseThread::TestBreak() will simply call C4DThread::TestDBreak().

                    Yep.

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      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;
                      }
                      
                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        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;
                        }
                        
                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          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)
                          {
                              // ...
                          }
                            
                          
                          
                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            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()?

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              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!

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                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

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post