1/****************************************************************************************
2
3 Copyright (C) 2015 Autodesk, Inc.
4 All rights reserved.
5
6 Use of this software is subject to the terms of the Autodesk license agreement
7 provided at the time of installation or download, or which otherwise accompanies
8 this software in either electronic or hard copy form.
9
10****************************************************************************************/
11
12//! \file fbxsync.h
13#ifndef _FBXSDK_CORE_SYNC_H_
14#define _FBXSDK_CORE_SYNC_H_
15
16#include <fbxsdk/fbxsdk_def.h>
17
18#if !defined(FBXSDK_ENV_WINSTORE) && !defined(FBXSDK_ENV_EMSCRIPTEN)
19
20#include <fbxsdk/core/sync/fbxclock.h>
21#include <fbxsdk/core/sync/fbxthread.h>
22
23#include <fbxsdk/fbxsdk_nsbegin.h>
24
25class FbxMutexImpl;
26class FbxSemaphoreImpl;
27class FbxGateImpl;
28
29/** A spinlock is the fastest and most simple thread lock mechanism available.
30 * It is very efficient since it does not use any operating system calls; it is only a test and set on an atomic variable,
31 * thus it is the fastest thread lock available. Spinlocks are efficient if threads are only likely to be blocked for a
32 * short period of time, as they avoid overhead from operating system process re-scheduling or context switching. However,
33 * spinlocks become wasteful if held for longer durations, both preventing other threads from running and requiring
34 * re-scheduling.
35 * \note Spinlocks does not support recursive locking. A thread attempting to lock the same spinlock twice will wait
36 * indefinitely.
37 */
38class FBXSDK_DLL FbxSpinLock
39{
40public:
41 FbxSpinLock();
42
43 /** Acquire the lock; thread will wait indefinitely until it is available. */
44 void Acquire();
45
46 /** Release the lock; this will allow other threads to acquire the lock if they are waiting. */
47 void Release();
48
49private:
50 FbxAtomic mSpinLock;
51};
52
53/** Mutually excluding thread lock mechanism.
54 * While the mutex is a much heavier implementation than a spinlock, it supports recursive locking; the same thread
55 * can safely lock the same mutex more than once without blocking. But it will have to be released as many times as
56 * it as been acquired before other threads can acquire the context. It is sometimes referred as a critical section.
57 * This is the heaviest thread lock implementation, but also the most secure.
58 */
59class FBXSDK_DLL FbxMutex
60{
61public:
62 /** Constructor
63 * \param pInitialOwnership If pInitialOwnership is true, the lock will be initialized as being locked by the
64 * current thread.
65 */
66 FbxMutex(bool pInitialOwnership=false);
67 virtual ~FbxMutex(); //!< Destructor
68
69 /** Acquire the lock; thread will wait indefinitely until it is available.
70 * \remarks The same thread can acquire the lock multiple times without blocking.
71 */
72 void Acquire();
73
74 /** Try acquiring the lock; thread will not wait if it is not available.
75 * \param pRetryCount The number of retries in case the lock is not available.
76 * \return True if the lock is acquired, false otherwise.
77 * \remarks The same thread can acquire the lock multiple times without blocking.
78 */
79 bool TryAcquire(unsigned int pRetryCount);
80
81 /** Release the lock; this will allow other threads to acquire the lock if they are waiting.
82 * \remarks Only the owner thread should call Release(), and it needs to be released as many times as it was
83 * acquired.
84 */
85 void Release();
86
87private:
88 FbxMutexImpl* mImpl;
89};
90
91/** Mutually excluding thread waiting mechanism with a counter.
92 * Semaphore are generally used in situations when the current thread needs to wait for other threads before
93 * proceeding to the next step. In other words, that thread waits a number of signals from other threads. This
94 * is the best mechanism to use to synchronize threads since it doesn't require an heavy critical section.
95 */
96class FBXSDK_DLL FbxSemaphore
97{
98public:
99 FbxSemaphore(); //!< Constructor
100 virtual ~FbxSemaphore(); //!< Destructor
101
102 /** Wait indefinitely until the semaphore as been signaled as many times as specified.
103 * \param pCount Number of signal to wait before this function returns.
104 * \return True if the wait exit without errors.
105 * \remarks If pCount is set to zero, this function returns immediately without waiting.
106 */
107 bool Wait(unsigned int pCount=1);
108
109 /** Signal the semaphore as many times as specified.
110 * \param pCount The number of signal to send to the semaphore.
111 * \return True if the semaphore was signaled without errors.
112 */
113 bool Signal(unsigned int pCount=1);
114
115private:
116 FbxSemaphoreImpl* mImpl;
117};
118
119/** A gate thread locking mechanism is very similar to a semaphore, except that when it is opened, any
120 * further call to wait will not wait until it is closed. It is generally used to block multiple threads
121 * until one of them open the gate to release them all.
122 */
123class FBXSDK_DLL FbxGate
124{
125public:
126 FbxGate(); //!< Constructor
127 virtual ~FbxGate(); //!< Destructor
128
129 /** Open the gate to release all threads waiting.
130 * \remarks All waiting threads will unblock until the gate is closed.
131 */
132 void Open();
133
134 /** Close the gate so that the next time a thread call Wait() it will be blocked. */
135 void Close();
136
137 /** Check if the gate is open.
138 * \return True if the gate is open, otherwise false.
139 */
140 bool IsOpen();
141
142 /** Wait indefinitely until the gate open.
143 * \return True if the wait completed without errors.
144 * \remarks If the gate is already open, this function returns immediately.
145 */
146 bool Wait();
147
148private:
149 FbxGateImpl* mImpl;
150};
151
152/** A simple stack of linked items that is multi-thread safe, protected by a spinlock.
153 */
154class FBXSDK_DLL FbxSyncStack
155{
156public:
157 //! A single link item to be used to construct the stack
158 struct Item
159 {
160 Item* mNext;
161 inline Item(){ mNext = NULL; }
162 inline Item* Set(Item* pNext){ return mNext = pNext; }
163 inline Item* Next(){ return mNext; }
164 };
165
166 //! Constructor
167 FbxSyncStack();
168
169 /** Add an item on the top of the stack.
170 * \param pItem The item to add on top of the stack.
171 */
172 void Push(Item* pItem);
173
174 /** Remove the item on the top of the stack.
175 * \return Returns the item on top of the stack, otherwise NULL if stack empty.
176 */
177 Item* Pop();
178
179private:
180 FbxSpinLock mLock;
181 Item* mTop;
182};
183
184#include <fbxsdk/fbxsdk_nsend.h>
185
186#endif /* !FBXSDK_ENV_WINSTORE && !FBXSDK_ENV_EMSCRIPTEN */
187
188#endif /* _FBXSDK_CORE_SYNC_H_ */
189