C4DThread Manual

About

C4DThread is the base class for custom classic threads in Cinema 4D. It can be used to perform operations on multiple cores or in the background.

Warning
Threads must not use any OS functions. This is strictly forbidden. The only system calls allowed are memory (de-)allocations.
For custom MAXON API threads see Threads Manual and Jobs Manual.
// This example contains a custom thread and a MessageData plugin.
// The thread renders the given BaseDocument and sends a core message when it has finished.
// This core message is caught by the MessageData plugin that will display the render result
// in the Picture Viewer.
// the render thread
class RenderThread : public C4DThread
{
private:
BaseDocument* _doc;
BaseBitmap* _bitmap;
public:
RenderThread() { _doc = nullptr; }
~RenderThread() { this->DeleteDoc(); }
void DeleteDoc() { BaseDocument::Free(_doc); }
// Sets the document and bitmap.
// The thread takes the ownership of the given BaseDocument.
void SetData(BaseDocument* const doc, BaseBitmap* const bitmap)
{
this->DeleteDoc();
_doc = doc;
_bitmap = bitmap;
}
void Main()
{
if (_doc == nullptr)
return;
if (_bitmap)
{
RenderData* const rdata = _doc->GetActiveRenderData();
const BaseContainer renderSettings = rdata->GetData();
BaseThread* const thread = this->Get();
RenderDocument(_doc, renderSettings, nullptr, nullptr, _bitmap, flags, thread);
}
// send core message that the thread finished
SpecialEventAdd(CUSTOM_ID_RENDER_FINISH);
this->DeleteDoc();
}
const Char* GetThreadName() { return "RenderThread"; }
};
// the MessageData plugin
class RenderThreadMessages : public MessageData
{
{
if (id == CUSTOM_ID_RENDER_FINISH)
{
if (g_displayBitmap)
{
ShowBitmap(g_displayBitmap);
}
}
return true;
}
};
// This example shows how to create and start a new custom thread instance.
// allocate thread if needed
if (g_renderThread == nullptr)
{
ifnoerr (g_renderThread = NewObj(RenderThread))
{
if (g_renderThread == nullptr)
return false;
}
}
// check if the thread is running
if (g_renderThread->IsRunning())
{
// stop the thread
g_renderThread->End(true);
}
// thread takes ownership of the document clone but not of the bitmap!
g_renderThread->SetData(documentClone, g_displayBitmap);
const Bool started = g_renderThread->Start();

Creation

A custom thread class is created by implementing a class based on C4DThread:

// This example shows the most simple C4DThread based custom thread.
class ExampleThread : public C4DThread
{
public:
ExampleThread() { }
virtual void Main() { }
virtual const Char* GetThreadName()
{
return "ExampleThread";
}
};

Now an instance of this custom thread class can be created and used:

// thread stored in a global variable
ExampleThread* g_exampleThread = nullptr;
static maxon::Result<void> CreateExampleThread()
{
// create thread instance on demand
if (g_exampleThread == nullptr)
{
g_exampleThread = NewObj(ExampleThread) iferr_return;
}
return maxon::OK;
}
// delete thread stored in the global variable
MAXON_INITIALIZATION(nullptr, []()
{
DeleteObj(g_exampleThread);
});

Custom Threads

A custom thread class has to implement these virtual functions:

// This example just prints some text to the console for 60 seconds.
// (TestDBreak() will stop it earlier)
void Main()
{
// save start time for TestDBreak()
_startTime = GeGetTimer();
// activity loop
for (Int32 i = 0; i < 60; ++i)
{
ApplicationOutput("perform background action " + String::IntToString(i));
// check if the thread should be stopped
if (this->TestBreak())
return;
GeSleep(1000);
}
}
// This example just returns the thread name
const Char* GetThreadName()
{
return "ExampleCustomThread";
}
// This example checks how long the thread is running.
// If the thread is running for longer than 20 seconds it should stop.
Bool TestDBreak()
{
if (_startTime == -1)
return true;
const Int32 time = GeGetTimer();
// check if 20000 milliseconds have passed
if ((time - _startTime) > 20000)
return true;
return false;
}
Note
To send a message from a thread to the main thread use SpecialEventAdd(). See Core Messages Manual.

Use

The custom thread can be started and stopped with these functions:

// This example starts the given thread object.
const Bool started = g_exampleThread->Start();
if (started == false)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
Note
The THREADPRIORITY should typically not be changed.

Read

Further thread properties are accessed with:

// check if the thread is running
if (g_exampleThread->IsRunning())
{
// stop the thread
g_exampleThread->End(true);
}

Further Reading