diff --git a/capture/build/win32/capture.vcxproj b/capture/build/win32/capture.vcxproj
index 94a84fbf..4d37aed9 100644
--- a/capture/build/win32/capture.vcxproj
+++ b/capture/build/win32/capture.vcxproj
@@ -135,6 +135,7 @@
+
@@ -160,6 +161,7 @@
+
diff --git a/capture/build/win32/capture.vcxproj.filters b/capture/build/win32/capture.vcxproj.filters
index d8dd1204..c815bac1 100644
--- a/capture/build/win32/capture.vcxproj.filters
+++ b/capture/build/win32/capture.vcxproj.filters
@@ -42,6 +42,9 @@
server
+
+ server
+
@@ -116,5 +119,8 @@
server
+
+ server
+
\ No newline at end of file
diff --git a/profiler/build/win32/Tracy.vcxproj b/profiler/build/win32/Tracy.vcxproj
index e600cbb0..192efb88 100644
--- a/profiler/build/win32/Tracy.vcxproj
+++ b/profiler/build/win32/Tracy.vcxproj
@@ -116,6 +116,7 @@
+
@@ -172,6 +173,7 @@
+
diff --git a/profiler/build/win32/Tracy.vcxproj.filters b/profiler/build/win32/Tracy.vcxproj.filters
index 98040182..393a035c 100644
--- a/profiler/build/win32/Tracy.vcxproj.filters
+++ b/profiler/build/win32/Tracy.vcxproj.filters
@@ -108,6 +108,9 @@
server
+
+ server
+
@@ -290,6 +293,9 @@
server
+
+ server
+
diff --git a/server/TracyTaskDispatch.cpp b/server/TracyTaskDispatch.cpp
new file mode 100644
index 00000000..19d227e3
--- /dev/null
+++ b/server/TracyTaskDispatch.cpp
@@ -0,0 +1,82 @@
+#include
+#include
+
+#include "TracyTaskDispatch.hpp"
+
+namespace tracy
+{
+
+TaskDispatch::TaskDispatch( size_t workers )
+ : m_exit( false )
+ , m_jobs( 0 )
+{
+ assert( workers >= 1 );
+
+ m_workers.reserve( workers );
+ for( size_t i=0; i& f )
+{
+ std::lock_guard lock( m_queueLock );
+ m_queue.emplace_back( f );
+ m_cvWork.notify_one();
+}
+
+void TaskDispatch::Queue( std::function&& f )
+{
+ std::lock_guard lock( m_queueLock );
+ m_queue.emplace_back( std::move( f ) );
+ m_cvWork.notify_one();
+}
+
+void TaskDispatch::Sync()
+{
+ std::unique_lock lock( m_queueLock );
+ while( !m_queue.empty() )
+ {
+ auto f = m_queue.back();
+ m_queue.pop_back();
+ lock.unlock();
+ f();
+ lock.lock();
+ }
+ m_cvJobs.wait( lock, [this]{ return m_jobs == 0; } );
+}
+
+void TaskDispatch::Worker()
+{
+ for(;;)
+ {
+ std::unique_lock lock( m_queueLock );
+ m_cvWork.wait( lock, [this]{ return !m_queue.empty() || m_exit.load( std::memory_order_acquire ); } );
+ if( m_exit.load( std::memory_order_acquire ) ) return;
+ auto f = m_queue.back();
+ m_queue.pop_back();
+ m_jobs++;
+ lock.unlock();
+ f();
+ lock.lock();
+ m_jobs--;
+ if( m_jobs == 0 && m_queue.empty() ) m_cvJobs.notify_one();
+ lock.unlock();
+ }
+}
+
+}
diff --git a/server/TracyTaskDispatch.hpp b/server/TracyTaskDispatch.hpp
new file mode 100644
index 00000000..de0f1c6e
--- /dev/null
+++ b/server/TracyTaskDispatch.hpp
@@ -0,0 +1,39 @@
+#ifndef __TRACYTASKDISPATCH_HPP__
+#define __TRACYTASKDISPATCH_HPP__
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace tracy
+{
+
+class TaskDispatch
+{
+public:
+ TaskDispatch( size_t workers );
+ ~TaskDispatch();
+
+ void Queue( const std::function& f );
+ void Queue( std::function&& f );
+
+ void Sync();
+
+private:
+ void Worker();
+
+ std::vector> m_queue;
+ std::mutex m_queueLock;
+ std::condition_variable m_cvWork, m_cvJobs;
+ std::atomic m_exit;
+ size_t m_jobs;
+
+ std::vector m_workers;
+};
+
+}
+
+#endif
diff --git a/update/build/win32/update.vcxproj b/update/build/win32/update.vcxproj
index d632fc36..0c8b86e3 100644
--- a/update/build/win32/update.vcxproj
+++ b/update/build/win32/update.vcxproj
@@ -134,6 +134,7 @@
+
@@ -157,6 +158,7 @@
+
diff --git a/update/build/win32/update.vcxproj.filters b/update/build/win32/update.vcxproj.filters
index 4d373293..61a2f097 100644
--- a/update/build/win32/update.vcxproj.filters
+++ b/update/build/win32/update.vcxproj.filters
@@ -36,6 +36,9 @@
server
+
+ server
+
@@ -104,5 +107,8 @@
server
+
+ server
+
\ No newline at end of file