#include "MultiThreadingExample.h" #include "../CommonInterfaces/CommonGraphicsAppInterface.h" #include "../CommonInterfaces/CommonRenderInterface.h" #include "../CommonInterfaces/CommonExampleInterface.h" #include "LinearMath/btTransform.h" #include "../CommonInterfaces/CommonGUIHelperInterface.h" #include "../RenderingExamples/TimeSeriesCanvas.h" #include "stb_image/stb_image.h" #include "Bullet3Common/b3Quaternion.h" #include "Bullet3Common/b3Matrix3x3.h" #include "../Utils/b3Clock.h" #include "../CommonInterfaces/CommonParameterInterface.h" #include "LinearMath/btAlignedObjectArray.h" #define stdvector btAlignedObjectArray #define MAGIC_RESET_NUMBER 64738 void SampleThreadFunc(void* userPtr,void* lsMemory); void* SamplelsMemoryFunc(); #include //#include "BulletMultiThreaded/PlatformDefinitions.h" #ifndef _WIN32 #include "b3PosixThreadSupport.h" b3ThreadSupportInterface* createThreadSupport(int numThreads) { b3PosixThreadSupport::ThreadConstructionInfo constructionInfo("testThreads", SampleThreadFunc, SamplelsMemoryFunc, numThreads); b3ThreadSupportInterface* threadSupport = new b3PosixThreadSupport(constructionInfo); return threadSupport; } #elif defined( _WIN32) #include "b3Win32ThreadSupport.h" b3ThreadSupportInterface* createThreadSupport(int numThreads) { b3Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("testThreads",SampleThreadFunc,SamplelsMemoryFunc,numThreads); b3Win32ThreadSupport* threadSupport = new b3Win32ThreadSupport(threadConstructionInfo); return threadSupport; } #endif struct SampleJobInterface { virtual void executeJob(int threadIndex)=0; }; struct SampleJob1 : public SampleJobInterface { float m_fakeWork; int m_jobId; SampleJob1(int jobId) :m_fakeWork(0), m_jobId(jobId) { } virtual ~SampleJob1() {} virtual void executeJob(int threadIndex) { printf("start SampleJob1 %d using threadIndex %d\n",m_jobId,threadIndex); //do some fake work for (int i=0;i<1000000;i++) m_fakeWork = b3Scalar(1.21)*m_fakeWork; printf("finished SampleJob1 %d using threadIndex %d\n",m_jobId,threadIndex); } }; struct SampleArgs { SampleArgs() { } b3CriticalSection* m_cs; btAlignedObjectArray m_jobQueue; void submitJob(SampleJobInterface* job) { m_cs->lock(); m_jobQueue.push_back(job); m_cs->unlock(); } SampleJobInterface* consumeJob() { SampleJobInterface* job = 0; m_cs->lock(); int sz = m_jobQueue.size(); if (sz) { job = m_jobQueue[sz-1]; m_jobQueue.pop_back(); } m_cs->unlock(); return job; } }; SampleArgs args; struct SampleThreadLocalStorage { int threadId; }; void SampleThreadFunc(void* userPtr,void* lsMemory) { printf("SampleThreadFunc thread started\n"); SampleThreadLocalStorage* localStorage = (SampleThreadLocalStorage*) lsMemory; SampleArgs* args = (SampleArgs*) userPtr; bool requestExit = false; while (!requestExit) { SampleJobInterface* job = args->consumeJob(); if (job) { job->executeJob(localStorage->threadId); } b3Clock::usleep(250); args->m_cs->lock(); int exitMagicNumber = args->m_cs->getSharedParam(1); requestExit = (exitMagicNumber==MAGIC_RESET_NUMBER); args->m_cs->unlock(); } printf("finished\n"); //do nothing } void* SamplelsMemoryFunc() { //don't create local store memory, just return 0 return new SampleThreadLocalStorage; } class MultiThreadingExample : public CommonExampleInterface { CommonGraphicsApp* m_app; b3ThreadSupportInterface* m_threadSupport; btAlignedObjectArray m_jobs; int m_numThreads; public: MultiThreadingExample(GUIHelperInterface* guiHelper, int tutorialIndex) :m_app(guiHelper->getAppInterface()), m_threadSupport(0), m_numThreads(8) { //int numBodies = 1; m_app->setUpAxis(1); m_app->m_renderer->enableBlend(true); } virtual ~MultiThreadingExample() { m_app->m_renderer->enableBlend(false); } virtual void renderScene() { } virtual void initPhysics() { b3Printf("initPhysics"); m_threadSupport = createThreadSupport(m_numThreads); for (int i=0;igetNumTasks();i++) { SampleThreadLocalStorage* storage = (SampleThreadLocalStorage*)m_threadSupport->getThreadLocalMemory(i); b3Assert(storage); storage->threadId = i; } args.m_cs = m_threadSupport->createCriticalSection(); args.m_cs->setSharedParam(0,100); for (int i=0;i<100;i++) { SampleJob1* job = new SampleJob1(i); args.submitJob(job); } int i; for (i=0;irunTask(B3_THREAD_SCHEDULE_TASK, (void*) &args, i); } b3Printf("Threads started"); } virtual void exitPhysics() { b3Printf("exitPhysics, stopping threads"); bool blockingWait =false; int arg0,arg1; args.m_cs->lock(); //terminate all threads args.m_cs->setSharedParam(1,MAGIC_RESET_NUMBER); args.m_cs->unlock(); if (blockingWait) { for (int i=0;iwaitForResponse(&arg0,&arg1); printf("finished waiting for response: %d %d\n", arg0,arg1); } } else { int numActiveThreads = m_numThreads; while (numActiveThreads) { if (m_threadSupport->isTaskCompleted(&arg0,&arg1,0)) { numActiveThreads--; printf("numActiveThreads = %d\n",numActiveThreads); } else { // printf("polling.."); } }; } delete m_threadSupport; b3Printf("Threads stopped"); for (int i=0;im_renderer && m_app->m_renderer->getActiveCamera()) { m_app->m_renderer->getActiveCamera()->setCameraDistance(dist); m_app->m_renderer->getActiveCamera()->setCameraPitch(pitch); m_app->m_renderer->getActiveCamera()->setCameraYaw(yaw); m_app->m_renderer->getActiveCamera()->setCameraTargetPosition(targetPos[0],targetPos[1],targetPos[2]); } } }; class CommonExampleInterface* MultiThreadingExampleCreateFunc(struct CommonExampleOptions& options) { return new MultiThreadingExample(options.m_guiHelper, options.m_option); }