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->GetDataInstanceRef();
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;
}
};
PyCompilerFlags * flags
Definition: ast.h:14
RENDERRESULT RenderDocument(BaseDocument *doc, const BaseContainer &rdata, ProgressHook *prog, void *private_data, BaseBitmap *bmp, RENDERFLAGS renderflags, BaseThread *th, WriteProgressHook *wprog=nullptr, void *data=nullptr)
void SpecialEventAdd(Int32 messageid, UInt p1=0, UInt p2=0)
Bool ShowBitmap(const Filename &fn)
Definition: c4d_basebitmap.h:435
Definition: c4d_basecontainer.h:48
Definition: c4d_basedocument.h:497
RenderData * GetActiveRenderData()
static void Free(BaseDocument *&bl)
const BaseContainer & GetDataInstanceRef() const
Definition: c4d_baselist.h:2517
Definition: c4d_thread.h:29
Definition: c4d_thread.h:63
BaseThread * Get() const
Definition: c4d_thread.h:91
virtual const Char * GetThreadName()=0
virtual void Main()=0
Definition: c4d_messagedata.h:65
virtual Bool CoreMessage(Int32 id, const BaseContainer &bc)=0
Definition: c4d_basedocument.h:143
maxon::Char Char
Definition: ge_sys_math.h:52
maxon::Bool Bool
Definition: ge_sys_math.h:51
maxon::Int32 Int32
Definition: ge_sys_math.h:56
RENDERFLAGS
Definition: ge_prepass.h:4691
@ NODOCUMENTCLONE
Set to avoid an automatic clone of the scene sent to RenderDocument().
const char * doc
Definition: pyerrors.h:226
// 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();
#define ifnoerr(...)
The opposite of iferr.
Definition: errorbase.h:393
#define NewObj(T,...)
Definition: newobj.h:108

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);
});
return OK
Definition: apibase.h:2735
#define MAXON_INITIALIZATION(...)
Definition: module.h:875
#define DeleteObj(obj)
Definition: newobj.h:159
#define iferr_scope
Definition: resultbase.h:1389
#define iferr_return
Definition: resultbase.h:1524

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;
}
Py_ssize_t i
Definition: abstract.h:645
void GeSleep(Int32 milliseconds)
Int32 GeGetTimer()
Definition: c4d_general.h:449
static String IntToString(Int32 v)
Definition: c4d_string.h:497
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
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);
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:67
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