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

BaseList2D::GetData
BaseContainer GetData()
Definition: c4d_baselist.h:2266
DeleteObj
#define DeleteObj(obj)
Definition: newobj.h:159
MessageData::CoreMessage
virtual Bool CoreMessage(Int32 id, const BaseContainer &bc)=0
GeGetTimer
Int32 GeGetTimer(void)
Definition: c4d_general.h:449
ifnoerr
#define ifnoerr(...)
The opposite of iferr.
Definition: errorbase.h:385
RenderDocument
RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
RENDERFLAGS
RENDERFLAGS
Definition: ge_prepass.h:4423
BaseThread
Definition: c4d_thread.h:28
maxon::OK
return OK
Definition: apibase.h:2518
SpecialEventAdd
void SpecialEventAdd(Int32 messageid, UInt p1=0, UInt p2=0)
iferr_return
#define iferr_return
Definition: resultbase.h:1434
MAXON_SOURCE_LOCATION
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:66
MessageData
Definition: c4d_messagedata.h:65
MAXON_INITIALIZATION
#define MAXON_INITIALIZATION(...)
Definition: module.h:733
C4DThread::Get
BaseThread * Get(void) const
Definition: c4d_thread.h:88
String::IntToString
static String IntToString(Int32 v)
Definition: c4d_string.h:495
maxon::Result< void >
iferr_scope
#define iferr_scope
Definition: resultbase.h:1343
Int32
maxon::Int32 Int32
Definition: ge_sys_math.h:58
ApplicationOutput
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:207
GeSleep
void GeSleep(Int32 milliseconds)
ShowBitmap
Bool ShowBitmap(const Filename &fn)
BaseDocument::Free
static void Free(BaseDocument *&bl)
C4DThread::GetThreadName
virtual const Char * GetThreadName(void)=0
BaseDocument::GetActiveRenderData
RenderData * GetActiveRenderData(void)
BaseBitmap
Definition: c4d_basebitmap.h:411
NewObj
#define NewObj(T,...)
Definition: newobj.h:108
RenderData
Definition: c4d_basedocument.h:132
Bool
maxon::Bool Bool
Definition: ge_sys_math.h:53
C4DThread
Definition: c4d_thread.h:62
Char
maxon::Char Char
Definition: ge_sys_math.h:54
BaseDocument
Definition: c4d_basedocument.h:485
C4DThread::Main
virtual void Main(void)=0
BaseContainer
Definition: c4d_basecontainer.h:47
RENDERFLAGS::NODOCUMENTCLONE
@ NODOCUMENTCLONE
Set to avoid an automatic clone of the scene sent to RenderDocument().