Multithreading
There are some utilities for using AngelScript in the multithreading environment.
Note
AngelScript does not support multithreading on all platforms.
-
inline bool asbind20::has_threads(const char *options = asGetLibraryOptions())
Check if
asGetLibraryOptions()doesn’t return"AS_NO_THREADS"
Initializing and Cleaning the Multithreading Environment
According to the official document, AngelScript needs some additional efforts to work in the multithreading environment.
The following functions are provided by the external header concurrent/threading.hpp.
-
inline void asbind20::concurrent::auto_thread_cleanup() noexcept
Mark this thread needs to clean up AngelScript data before terminating.
It’s safe to call this function for the second time in the same thread.
Note
Remember to call this function in any thread other than main thread to prevent memory leak.
-
inline void asbind20::concurrent::prepare_multithread(asIThreadManager *external_mgr = nullptr)
Call this function in the main thread to prepare for multithreading.
Warning
Call this function before any script engine is created, and make sure global variables don’t contain any script engine that may be released after
asUnprepareMultithreadbeing called.
Example code:
#include <thread>
#include <asbind20/asbind.hpp>
#include <asbind20/concurrent/threading.hpp>
int main()
{
if(!asbind20::has_threads())
{
std::cerr << "AS_NO_THREADS" << std::endl;
return 1;
}
using namespace asbind20;
concurrent::prepare_multithread();
auto engine = make_script_engine();
auto* m = engine->GetModule(
"script_multithreading", asGM_ALWAYS_CREATE
);
m->AddScriptSection(
"script_multithreading",
"int fn(int arg) { return arg * 2; }"
);
m->Build();
auto* f = m->GetFunctionByName("fn");
std::condition_variable cv;
std::mutex mx;
int result = -1;
auto helper = [&, f](int arg)
{
concurrent::auto_thread_cleanup();
{
using namespace std::chrono_literals;
request_context ctx(engine);
std::this_thread::sleep_for(3ms); // Emulates running a complex script
auto r = script_invoke<int>(ctx, f, arg);
std::unique_lock lock(mx);
result = r.value();
}
cv.notify_all();
};
std::thread thr(helper, 10);
thr.detach();
{
std::unique_lock lock(mx);
std::cv_status st = cv.wait(lock);
}
assert(result == 20);
return 0;
}
Locks
The AngelScript library provides two locks.
Wrapper for
asAcquireSharedLock()andasReleaseSharedLock()
-
constexpr detail::as_exclusive_lock_t asbind20::as_exclusive_lock = {}
Wrapper for
asAcquireExclusiveLock()andasReleaseExclusiveLock()
The weak reference flag (asILockableSharedBool*) is also lockable.
-
class lockable_shared_bool
Helper for
asILockableSharedBool*This class can be helpful for implementing weak reference support.
Public Functions
-
inline void lock()
Lock the flag.
-
inline void unlock() noexcept
Unlock the flag.
-
inline void lock()
Example code:
{
std::lock_guard guard(asbind20::as_exclusive_lock);
// Do something...
}
Atomic Reference Counting
-
class atomic_counter
Atomic counter for multithreading.
This wraps the
asAtomicIncandasAtomicDec.Note
Its initial value will be 1.
Increment and decrement operators
Even the prefix increment / decrement will return
intvalue directly, which is similar to how thestd::atomic<T>does.-
inline int operator++() noexcept
-
inline int operator--() noexcept
Public Types
-
using value_type = int
Public Functions
-
inline atomic_counter() noexcept
Construct a new atomic counter and set the counter value to 1.
-
atomic_counter(const atomic_counter&) = default
-
inline atomic_counter(int val) noexcept
-
~atomic_counter() = default
-
atomic_counter &operator=(const atomic_counter&) noexcept = default
-
inline atomic_counter &operator=(int val) noexcept
-
bool operator==(const atomic_counter&) const = default
-
inline int inc() noexcept
-
inline int dec() noexcept
-
inline operator int() const noexcept
-
inline int operator++() noexcept
For garbage collected types, please read the official document about thread safety and GC.