AGX Dynamics 2.42.2.1
Loading...
Searching...
No Matches
Thread.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#pragma once
18
19#ifdef _MSC_VER
20# pragma warning(push)
21# pragma warning( disable: 4275 ) // warning C4275: non dll-interface class
22# pragma warning(disable: 4251) // warning C4251: class X needs to have dll-interface to be used by clients of class Y
23#endif
24
25
26#include <agx/agx.h>
27#include <agx/Vector.h>
28#include <agx/HashTable.h>
29#include <agx/Timer.h>
30#include <agx/Task.h>
32
35
36#include <agx/Job.h>
37#include <agx/Uuid.h>
38#include <agx/Notify.h>
39
40#include <queue>
41#include <thread>
42
43
44// Set to 1 to enable thread timeline reporting of internal steps
45#define ENABLE_VERBOSE_THREAD_TIMELINE 0
46
47
48#define AGX_MAX_NUM_THREADS 1024
49
50
51extern "C"
52{
54}
55
56namespace agxData
57{
58 class EntityStorage;
59 class EntityModel;
60}
61
62
63
64
65
66namespace agx
67{
68 class TiXmlElement;
69 class Task;
70
71
72 // AGX_DECLARE_POINTER_TYPES(Thread);
73 // AGX_DECLARE_VECTOR_TYPES(Thread);
74
75
76
83 {
84 public:
85
90 THREAD_NEW = 0, // When a BasicThread is created
91 THREAD_RUNNING = 1, // start has been called
92 THREAD_DETACHED = 2, // detach has been called
93 THREAD_DONE = 3, // After run() is done executing
94 THREAD_JOINED = 4, // After join() has been called
95 THREAD_CANCELLED = 5 // After cancel but before join
96 };
97
102
103 BasicThread( const BasicThread& other ) = delete;
104
105 BasicThread& operator=(const BasicThread& rhs ) = delete;
106
110 virtual ~BasicThread() = default;
111
116 virtual void run() { }
117
125 bool start();
126
134 void cancel();
135
139 bool join();
140
141
145 void detach();
146
150 inline bool joinable();
151
155 inline unsigned int getThreadState();
156
157
158
159
174
175
179 static std::thread::native_handle_type getCurrentThreadHandle();
180
181
182 private:
183 void launchThread();
184
185 protected:
186 std::thread m_handle;
187 std::atomic< unsigned int> m_state;
188 private:
189 std::mutex m_handleMutex;
190 };
191
192
193
199 {
200 public:
201
202
203 // The types used when communicating with the thread local storage facilities.
204 // The key type is an integer type and the data type is a pointer type.
205 #ifdef _WIN32
206 typedef unsigned long ThreadStorageKey; // Should be DWORD
207 typedef void* ThreadStorageData; // Should be LPVOID
208 #else
209 typedef pthread_key_t ThreadStorageKey;
210 typedef void* ThreadStorageData;
211 #endif
212
213 typedef std::mt19937 RandomGenerator;
214
218 bool start();
219
223 void stop();
224
231 Index getId() const;
232
244
249
255 static std::string getCurrentThreadDescription();
256
260 static Thread *getThread(size_t id);
261
265 static Thread *getMainThread();
266
272
278
284
290 RandomGenerator& getRandomGenerator();
291
292
296 static bool isMainThread();
297
298
302 static void shutdown();
303
304 static bool isShuttingDown();
305
306
308 static void setEnableJobTimeline(bool flag);
309 static bool getEnableJobTimeline();
310
320 UInt64 startTick, UInt64 endTick,
321 const char* description,
322 const char* extraDataTitle = nullptr,
323 agx::Real64 extraData = 0.0);
324
328 Real getOverheadTime() const;
329
334
335 // Allocations
336 // void *allocateBytes(size_t numBytes);
337 // void *deallocateBytes(void *ptr);
338
344
345
346 // Main thread is normally allocated automatically, special usage before main is entered
347 static void initThreadSystem();
348
349 // Dump profiling logs, called by Simulation
350 static void exportAllTimelines();
351 static void resetStartTick();
352 static void flushTimelineLogs();
353
354
355 /*
356 * Methods used for manipulating the thread local storage.
357 */
358
367
368 static bool immediateLogging;
369 static int log(const char *format, ...);
370 static void flushLogs();
372
374
375
376 static void addTask(Task *task);
377
378 // Threads that aren't "real" AGX threads, i.e., registered threads, get
379 // a pseudo-ID in this table. These IDs are unrelated from the IDs of the
380 // "real" AGX threads.
383
384 protected:
386 Thread(const Thread&) = delete;
387 virtual ~Thread();
388
389 private:
390 friend void AGXCORE_EXPORT setNumThreads(size_t numThreads);
392
393 class MainThreadSingleton;
394 static Thread *initMainThread();
395
396 static void performNumThreadsChange();
397
398 virtual void run();
399
400 void freeDefaultStorages();
401 void spawn(Job *job);
402 void sortInsertJob(Job *job);
403
404 void activate();
405 void completeFrame(Task *task);
406
407 bool isActive() const;
408
409
410 template <bool THREAD_TIMELINE_STATISTICS>
411 void doWork();
412
413 void doWork();
414 void blockingDoWork();
415
416 void stealWork();
417 void wakeupThreads();
418 void pushTargetJob(Thread *target, Job *job, bool activateTarget = true);
419 static void taskCompleted(Task *task);
420
421 void initialize();
422 void sleep();
423
424 Job *getExecutionJob();
425
426 Index getRandomOtherThreadId(Index excludeIndex = InvalidIndex);
427
428 friend class Block;
429
430 friend class Job;
431 friend class Notify;
432
433 private:
434 Notify::ThreadData *getNotifyData();
436
437 friend class Task;
438
439 // Simple linear congruential generator
440 class FastRandom
441 {
442 public:
443 FastRandom(UInt32 seed);
444 FastRandom();
445
446 UInt32 operator() ();
447
448 private:
449 static const UInt32 mod = ((1ULL << 32) - 5);
450 static const UInt32 mul = 69070U;
451
452 void init(UInt32 seed);
453
454 private:
455 UInt32 m_state;
456 };
457
458 FastRandom m_fastRandom;
459
460 struct Frame
461 {
462 inline Frame(Task *t = nullptr) : task(t), done(false) {}
463 inline Frame& operator=(const Frame& other) {task = other.task; done = other.done.load(); return *this;}
464 Task *task;
465 std::atomic<bool> done;
466 };
467
468 #define AGX_THREAD_FRAME_STACK_MAX_DEPTH 64
469 Frame m_frames[AGX_THREAD_FRAME_STACK_MAX_DEPTH];
470 size_t m_numFrames;
471 size_t m_activationDepth;
472 std::atomic<Int32> m_activationCount;
473
474
475 struct JobCompare
476 {
477 AGX_FORCE_INLINE bool operator() (const Job *lhs, const Job *rhs) const
478 {
479 return lhs->getCostEstimate() < rhs->getCostEstimate();
480 }
481 };
482
483 Block m_startBlock;
484 Block m_runBlock;
485
486 Thread *m_listNodeNext;
487
488 using JobQueue = std::priority_queue<Job *, agx::VectorPOD<Job *>, JobCompare>;
489
490 JobQueue m_sharedJobs;
491 JobPtrVector m_localJobs;
492 JobPtrVector m_pushedJobs;
493
494 std::atomic<Int32> m_pushCounter;
495 std::atomic<bool> m_running;
496
497 agx::SpinMutex m_timelineMutex;
498 char m_padding_1[64-sizeof(agx::SpinMutex)];
499 agx::SpinMutex m_jobMutex;
500 char m_padding_2[64-sizeof(agx::SpinMutex)];
501 agx::SpinMutex m_pushMutex;
502 AGX_STATIC_ASSERT(sizeof(agx::SpinMutex) <= 64);
503
504 Index m_id;
505
506 Timer m_overheadTimer;
507 Timer m_wakeupTimer;
508 Timer m_sleepTimer;
509
510 UInt64 m_savedRegisterState;
511
512 bool m_isSleeping;
513
514 agx::UuidGenerator m_uuidGenerator;
515 std::random_device m_randomDevice;
516 RandomGenerator m_mersienneTwister;
517
518 private:
519
521 void registerContainerAllocation(Container *container);
522 void unregisterContainerAllocation(Container *container);
523 void *allocateScratchPadBuffer(size_t numBytes);
524 void deallocateScratchPadBuffer(void *buffer, size_t numBytes);
525
526 struct ScratchPadArea
527 {
528 ScratchPadArea() : buffer(nullptr), end(nullptr), head(nullptr), m_allocator("ScratchPad")
529 {}
530
531 ~ScratchPadArea() { m_allocator.deallocateBytes(buffer); }
532
533 char *buffer;
534 char *end;
535 char *head;
536 ByteAllocator m_allocator;
537 VectorPOD<Container *> m_activeAllocations;
538 };
539
540 ScratchPadArea m_scratchPad;
541
542 agxData::EntityStorageRef m_timelineEntries;
543
544
545 static Thread *s_threads[AGX_MAX_NUM_THREADS];
546 static Thread *s_mainThread;
547 static Callback1<Task *> s_taskCompletionCallback;
548
549 static bool s_enableJobTimeline;
550
551 static std::exception_ptr s_unhandledException;
552
553
554 struct LocalTimelineEntry
555 {
556 LocalTimelineEntry()
557 : jobType(UNKNOWN)
558 , startTick(0)
559 , endTick(0)
560 , poolSize(0)
561 , costEstimate(0)
562 , message(nullptr)
563 , job(nullptr)
564 , extraDataTitle(nullptr)
565 , extraData(0.0)
566 {}
567
568 enum JobType { PRE, DISPATCH, POST, UNKNOWN };
569
570 agx::TaskRef task;
571 JobType jobType;
572 agx::UInt64 startTick;
573 agx::UInt64 endTick;
574 agx::UInt32 poolSize;
575 agx::UInt32 costEstimate;
576 const char* message;
577 void* job;
578
579 const char* extraDataTitle;
580 agx::Real64 extraData;
581 };
582
583 Vector<LocalTimelineEntry> m_localTimelineEntries;
584 AGX_DECLARE_POINTER_TYPES(TimelineExportKernel);
585
586
587 void exportTimelineEntries();
588 void reportTimelineJob(Job *job);
589 void pushTimelineEntry(const LocalTimelineEntry& entry);
590
592 class LogChunk : public Referenced
593 {
594 public:
595 LogChunk(size_t numBytes);
596 char* buffer;
597 char* head;
598 char* end;
599 LogChunkRef next;
600 size_t numAvailable();
601
602 protected:
603 virtual ~LogChunk();
604 };
605
606 struct LogEntry
607 {
608 LogEntry();
609 LogEntry(agx::UInt64 timestamp_, const char* message_);
610 agx::UInt64 timestamp;
611 const char* message;
612 };
613
614 int logImplementation(const char* format, va_list ap);
615 static int cmpLogEntry(const LogEntry& entry1, const LogEntry& entry2);
616
617 LogChunkRef m_logChunk;
618 VectorPOD<LogEntry> m_logEntries;
619
620 typedef HashTable<agxData::EntityModel*, ref_ptr<Referenced>> DefaultStorageTable;
621 DefaultStorageTable m_defaultStorageTable;
622 };
623
625
626
627
628
629
630
631
632 /* Implementation */
634
636 {
637 return m_handle.joinable();
638 }
639
640
641
642 inline unsigned int BasicThread::getThreadState()
643 {
644 return m_state.load();
645 }
646
647
648
650 {
651 return m_id;
652 }
653
655 {
656 agxAssert(s_threads[id]);
657 return s_threads[id];
658 }
659
661 {
662 agxAssert(s_mainThread);
663 return s_mainThread;
664 }
665
667 AGX_FORCE_INLINE bool Thread::isActive() const { return m_activationCount.load() > 0; }
668
670 {
671 return m_mersienneTwister;
672 }
673
674 AGX_FORCE_INLINE Real Thread::getOverheadTime() const { return Real(m_overheadTimer.getTime()); }
675
676
677 inline int Thread::log(const char *format, ...)
678 {
679 va_list arguments;
680 va_start(arguments, format);
681 int result = Thread::getCurrentThread()->logImplementation(format, arguments);
682 va_end(arguments);
683 return result;
684 }
685
686
687 #if 0
688 AGX_FORCE_INLINE void *Thread::allocateBytes(size_t numBytes)
689 {
690 return m_byteAllocator.allocate(numBytes);
691 }
692
693 AGX_FORCE_INLINE void *Thread::deallocateBytes(void *ptr)
694 {
695 m_byteAllocator.deallocateBytes(ptr);
696 }
697
698 template <typename T>
699 AGX_FORCE_INLINE T *Thread::allocate()
700 {
701 return this->getPool<T>()->allocate();
702 }
703
704 template <typename T>
705 AGX_FORCE_INLINE void Thread::deallocate(T *ptr)
706 {
707 this->getPool<T>()->deallocate(ptr);
708 }
709
710
711 template <typename T>
712 AGX_FORCE_INLINE T *Thread::create()
713 {
714 return this->getPool<T>()->create();
715 }
716
717 template <typename T>
718 AGX_FORCE_INLINE void Thread::destroy(T *ptr)
719 {
720 this->getPool<T>()->destroy(ptr);
721 }
722
723 template <typename T>
724 AGX_FORCE_INLINE MemoryPool<T> *Thread::getPool()
725 {
726 uint32_t id = agxData::getType<T>()->getId();
727 if (id >= m_pools.size())
728 m_pools.resize(id+1, 0);
729
730 if (!m_pools[id])
731 m_pools[id] = new MemoryPool<T>;
732
733 return static_cast<MemoryPool<T> *>(m_pools[id]);
734 }
735
736 void setCurrentConstructionObject(void *ptr);
737 void *getCurrentConstructionObject();
738 #endif
739
740
741
742
743
744 AGX_FORCE_INLINE void *Thread::allocateScratchPadBuffer(size_t numBytes)
745 {
746 numBytes = (numBytes + 31) & ~size_t(31);
747
748 /* Check if scratch pad is too small, which requires reallocation and updates to all existing container allocations */
749 if (m_scratchPad.head + numBytes > m_scratchPad.end)
750 {
751 size_t currentSize = m_scratchPad.end - m_scratchPad.buffer;
752 const Real growFactor = 1.5;
753 size_t newSize = (size_t)( Real(currentSize + numBytes) * growFactor );
754 // printf("Reallocating scratch pad for thread %d from %u to %u KB\n", this->getId(), (unsigned)(currentSize/1024), (unsigned)(newSize/1024));
755
756 char *newBuffer = (char *)m_scratchPad.m_allocator.allocateBytes(newSize, 64);
757 agxAssertN(newBuffer, "Thread %d could not allocate %u bytes for job scratch pad!", this->getId(), (unsigned)newSize);
758 if (!newBuffer)
759 return nullptr;
760
761 /* Copy active allocations */
762 size_t numUsed = m_scratchPad.head - m_scratchPad.buffer;
763
764 if ( numUsed > 0 )
765 memcpy(newBuffer, m_scratchPad.buffer, numUsed);
766
767 m_scratchPad.m_allocator.deallocateBytes(m_scratchPad.buffer);
768
769 /* Update buffer pointers for active allocations */
770 for (size_t i = 0; i < m_scratchPad.m_activeAllocations.size(); ++i)
771 {
772 Container *container = m_scratchPad.m_activeAllocations[i];
773
774 if (container->m_buffer)
775 {
776 ptrdiff_t offset = (char *)container->m_buffer - (char *)m_scratchPad.buffer;
777 container->m_buffer = newBuffer + offset;
778 }
779 }
780
781 m_scratchPad.buffer = newBuffer;
782 m_scratchPad.end = m_scratchPad.buffer + newSize;
783 m_scratchPad.head = m_scratchPad.buffer + numUsed;
784 }
785
786 void *mem = m_scratchPad.head;
787 m_scratchPad.head += numBytes;
788
789 return mem;
790 }
791
792 AGX_FORCE_INLINE void Thread::deallocateScratchPadBuffer(void *buffer, size_t numBytes)
793 {
794 agxAssert(!buffer || (buffer >= m_scratchPad.buffer && buffer < m_scratchPad.end));
795
796 if ((char *)buffer + numBytes == m_scratchPad.head)
797 m_scratchPad.head = (char *)buffer;
798 }
799
800 AGX_FORCE_INLINE void Thread::registerContainerAllocation(Container *container)
801 {
802 m_scratchPad.m_activeAllocations.push_back(container);
803 }
804
805 #ifdef AGX_DEBUG
806 AGX_FORCE_INLINE void Thread::unregisterContainerAllocation(Container *container)
807 #else
808 AGX_FORCE_INLINE void Thread::unregisterContainerAllocation(Container * /* container */)
809 #endif
810 {
811 agxAssert1(!m_scratchPad.m_activeAllocations.empty() && container == m_scratchPad.m_activeAllocations.back(), "LIFO order required!");
812 m_scratchPad.m_activeAllocations.pop_back();
813
814 /* Reset scratch pad, removing any holes from reallocations */
815 if (m_scratchPad.m_activeAllocations.empty())
816 m_scratchPad.head = m_scratchPad.buffer;
817 }
818
819}
820
821
822#if ENABLE_VERBOSE_THREAD_TIMELINE
823 #define AGX_BEGIN_TIMELINE_REPORT(variable) \
824 auto variable ## _begin_time = agx::Timer::getCurrentTick()
825
826 #define AGX_END_TIMELINE_REPORT(variable, title) \
827 auto variable ## _end_time = agx::Timer::getCurrentTick(); \
828 agx::Thread::getCurrentThread()->reportSystemJob( variable ## _begin_time , variable ## _end_time, title);
829
830 #define AGX_END_TIMELINE_REPORT_DATA(variable, title, title2, data) \
831 auto variable ## _end_time = agx::Timer::getCurrentTick(); \
832 agx::Thread::getCurrentThread()->reportSystemJob( variable ## _begin_time , variable ## _end_time, title, title2, data)
833#else
834 #define AGX_BEGIN_TIMELINE_REPORT(variable)
835 #define AGX_END_TIMELINE_REPORT(variable, title)
836 #define AGX_END_TIMELINE_REPORT_DATA(variable, title, title2, data)
837#endif
838
839
840#ifdef _MSC_VER
841# pragma warning(pop)
842#endif
#define AGX_DECLARE_POINTER_TYPES(type)
Definition: Referenced.h:254
#define AGX_THREAD_FRAME_STACK_MAX_DEPTH
Definition: Thread.h:468
#define AGX_MAX_NUM_THREADS
Definition: Thread.h:48
void agxFlushThreadLogs()
#define AGXCORE_EXPORT
#define AGXPHYSICS_EXPORT
An attribute container.
An abstract description of a data entity stored using SOA (structure of arrays) pattern in a EntitySt...
Definition: EntityModel.h:64
Data storage for a collection of entity instances of a specified EntityModel.
Definition: EntityStorage.h:73
Basic wrapper class aroud std::thread.
Definition: Thread.h:83
BasicThread & operator=(const BasicThread &rhs)=delete
BasicThread()
Default constructor.
bool setThreadAffinity(agx::UInt64 cpumask)
Thread Affinity can be used to influence on which logical cores threads are scheduled and allowed to ...
BasicThread(const BasicThread &other)=delete
void detach()
Detaches the thread to the background.
void cancel()
Threads should normally not need to be killed.
virtual ~BasicThread()=default
Destructor.
std::atomic< unsigned int > m_state
Definition: Thread.h:187
bool join()
Joins the thread.
virtual void run()
This method is invoked by start.
Definition: Thread.h:116
std::thread m_handle
Definition: Thread.h:186
bool joinable()
True if thread is joinable.
Definition: Thread.h:635
ThreadState
States for the thread.
Definition: Thread.h:89
unsigned int getThreadState()
Returns the current thread state.
Definition: Thread.h:642
bool start()
Launches the thread.
static std::thread::native_handle_type getCurrentThreadHandle()
Return a native_handle for the current executing thread.
Block synchronization primitive.
The Container is the base class for several of the container classes proided by AGX,...
Definition: Container.h:35
The object defining a frame of reference and providing transformations operations.
Definition: agx/Frame.h:68
An abstract job/workblock representation, which allows work threads to execute arbitrary tasks.
Definition: Job.h:61
Inheritance with partial specialization due to bug with ref_ptr containers.
Class for handling logging of messages.
Definition: Notify.h:64
Spin-lock mutex.
Definition: SpinMutex.h:47
A representation of a generic task.
Definition: Task.h:57
agx::Thread is a representation of an OS specific implementation of a computational thread.
Definition: Thread.h:199
static void writePerThreadStorage(ThreadStorageKey key, ThreadStorageData data)
Write to the thread-local location owned by the currently executing thread.
HashTable< Thread *, Index > ThreadIdTable
Definition: Thread.h:381
friend void AGXPHYSICS_EXPORT shutdown()
Shutdown of the AGX Dynamics API will be done when the number of shutdown matches the number of calls...
static void resetStartTick()
agx::Uuid generateUuid()
Generates a unique universal identifier.
void stop()
Stop the thread.
static void makeCurrentThreadMainThread()
Register current thread as main thread.
static int log(const char *format,...)
Definition: Thread.h:677
static Thread * getCurrentThread()
static void freePerThreadStorage(ThreadStorageKey key)
Deallocate the storage location.
static void addTask(Task *task)
agxData::EntityStorage * getDefaultStorage(agxData::EntityModel *entity)
Thread(Index id)
static bool isMainThread()
Definition: Thread.h:666
void resetOverheadTime()
Reset the thread overhead time.
bool start()
Start the thread.
static void flushLogs()
void * ThreadStorageData
Definition: Thread.h:210
Thread(const Thread &)=delete
static void initThreadSystem()
static void shutdown()
Shutdown the threading system.
void reportSystemJob(UInt64 startTick, UInt64 endTick, const char *description, const char *extraDataTitle=nullptr, agx::Real64 extraData=0.0)
Add an entry to the job duration log.
static std::string getCurrentThreadDescription()
static void setEnableJobTimeline(bool flag)
Enable or disable job timeline statistics.
static Thread * registerAsAgxThread()
Register the current thread as an AGX thread.
friend void AGXCORE_EXPORT setNumThreads(size_t numThreads)
Set the number of threads to use (including the main thread).
pthread_key_t ThreadStorageKey
Definition: Thread.h:209
std::mt19937 RandomGenerator
Definition: Thread.h:213
Index getIndex() const
Get an index suitable for use when storing per-thread data in e.g.
static ThreadStorageKey allocatePerThreadStorage()
Allocate a storage location that is unique for each thread.
agxData::EntityStorageRef popTimelineEntryStorage()
RandomGenerator & getRandomGenerator()
Return a reference to the mersienne twister used for generating random numbers.
Definition: Thread.h:669
static bool immediateLogging
Definition: Thread.h:368
virtual ~Thread()
static void flushTimelineLogs()
static bool isShuttingDown()
static Thread * getThread(size_t id)
Definition: Thread.h:654
static Thread * getMainThread()
Definition: Thread.h:660
static bool getEnableJobTimeline()
static ThreadStorageData readPerThreadStorage(ThreadStorageKey key)
Read the thread-local value for the currently executing thread associated with the given key.
static void unregisterAsAgxThread()
Remove agx attributes from current thread.
Index getId() const
Returns the thread's AGX thread ID, a value between 0 and N-1, for AGX's internal threads,...
Definition: Thread.h:649
Real getOverheadTime() const
Definition: Thread.h:674
static Thread::ThreadIdTable * getPromotedThreads()
static void exportAllTimelines()
Generator of UUID values based on V4 http://en.wikipedia.org/wiki/Universally_unique_identifier.
Definition: Uuid.h:232
A UUID, or Universally unique identifier, is intended to uniquely identify information in a distribut...
Definition: Uuid.h:42
Vector containing 'raw' data.
Definition: agx/Vector.h:246
#define agxAssert1(expr, msg)
Definition: debug.h:144
#define agxAssertN(expr, format,...)
Definition: debug.h:145
#define agxAssert(expr)
Definition: debug.h:143
#define AGX_STATIC_ASSERT(X)
Definition: macros.h:23
#define AGX_FORCE_INLINE
Definition: macros.h:58
Contains classes for low level data storage for AGX.
Definition: Container.h:23
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
double Real64
Definition: Real.h:44
uint32_t UInt32
Definition: Integer.h:32
uint64_t UInt64
Definition: Integer.h:33
agx::VectorPOD< Thread * > ThreadPtrVector
Definition: Thread.h:624
LinearProbingHashSetImplementation< KeyT, HashT >::iterator end(LinearProbingHashSetImplementation< KeyT, HashT > &set)
double Real
Definition: Real.h:41
VectorPOD< class Job * > JobPtrVector
Definition: Job.h:49
void AGXPHYSICS_EXPORT init()
Initialize AGX Dynamics API including thread resources and must be executed before using the AGX API.
UInt32 Index
Definition: Integer.h:44