patterncsharpMinor
Low-lock Multi-threading Implementation
Viewed 0 times
multilowthreadingimplementationlock
Problem
I'm designing in my spare time a game engine (for fun, not so much for profit, haha). I wanted to design the 'core pipeline' as efficiently as possible. Having a quad-core CPU, I decided to take advantage of parallel processing.
I wanted to implement a lock-free algorithm (or at least, low-locking) to make the pipeline as quick as possible (and to avoid expensive things like lock contention, kernel-mode locking, and context switching as much as possible).
Without further preamble, here is my implementation (slightly shortened):
EnginePipeline.cs
```
public static partial class EnginePipeline {
private static EngineComponent[] componentPipeline;
private static volatile bool isRunning = false;
private static volatile bool exitFlag = false;
private static Thread[] threadPool;
private static EngineComponent currentComponent;
private static WorkloadSet currentWorkloads = new WorkloadSet(100);
private static void InitThreadPool() {
int numLogicalCores = Environment.ProcessorCount;
int poolSize = numLogicalCores;
if (PipelineConfig.MaxThreads > 0 && numLogicalCores > PipelineConfig.MaxThreads) poolSize = PipelineConfig.MaxThreads;
// One less than the number of cores because the master thread will be used too
poolSize -= 1;
if (poolSize
/// Run the pipeline. This method will block indefinitely until something calls
/// or .
///
public static void Run() {
isRunning = true;
SpinWait completionWaiter = new SpinWait();
PipelineWorkload workload = new PipelineWorkload();
while (!exitFlag) {
for (int i = 0; i < componentPipeline.Length; ++i) {
// Set current component
Volatile.Write(ref currentComponent, componentPipeline[i]);
// Calculate the workloads
int range = currentComponent.GetRange();
int blockSize = currentComponent.actualBlockSize;
I wanted to implement a lock-free algorithm (or at least, low-locking) to make the pipeline as quick as possible (and to avoid expensive things like lock contention, kernel-mode locking, and context switching as much as possible).
Without further preamble, here is my implementation (slightly shortened):
EnginePipeline.cs
```
public static partial class EnginePipeline {
private static EngineComponent[] componentPipeline;
private static volatile bool isRunning = false;
private static volatile bool exitFlag = false;
private static Thread[] threadPool;
private static EngineComponent currentComponent;
private static WorkloadSet currentWorkloads = new WorkloadSet(100);
private static void InitThreadPool() {
int numLogicalCores = Environment.ProcessorCount;
int poolSize = numLogicalCores;
if (PipelineConfig.MaxThreads > 0 && numLogicalCores > PipelineConfig.MaxThreads) poolSize = PipelineConfig.MaxThreads;
// One less than the number of cores because the master thread will be used too
poolSize -= 1;
if (poolSize
/// Run the pipeline. This method will block indefinitely until something calls
/// or .
///
public static void Run() {
isRunning = true;
SpinWait completionWaiter = new SpinWait();
PipelineWorkload workload = new PipelineWorkload();
while (!exitFlag) {
for (int i = 0; i < componentPipeline.Length; ++i) {
// Set current component
Volatile.Write(ref currentComponent, componentPipeline[i]);
// Calculate the workloads
int range = currentComponent.GetRange();
int blockSize = currentComponent.actualBlockSize;
Solution
you have a little bit of rewriting that can be done on this chunk of code
I want to change a Variable name, and I am sure that there are more than should be changed as well. but I have only singled out this method so far.
so this
should be this
and then instead of counting the logical cores/processors and changing the
And then following the logic of that ternary statement
but, I think there will be issues. What if
private static void InitThreadPool() {
int numLogicalCores = Environment.ProcessorCount;
int poolSize = numLogicalCores;
if (PipelineConfig.MaxThreads > 0 && numLogicalCores > PipelineConfig.MaxThreads) poolSize = PipelineConfig.MaxThreads;
// One less than the number of cores because the master thread will be used too
poolSize -= 1;
if (poolSize < 0) poolSize = 0;
threadPool = new Thread[poolSize];
for (int i = 0; i < poolSize; i++) {
threadPool[i] = new Thread(ThreadWaitForWork) {
Name = "OphSlave-" + i,
IsBackground = true
};
threadPool[i].Start();
}
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
Thread.CurrentThread.Name = "OphMaster";
}I want to change a Variable name, and I am sure that there are more than should be changed as well. but I have only singled out this method so far.
so this
private static Thread[] threadPool;should be this
private static Thread[] threads;and then instead of counting the logical cores/processors and changing the
poolSize variable so many times, just use a ternary statement to assign the value you want to the poolSize variable like this// One less than the number of cores because the master thread will be used too
int poolSize = (PipelineConfig.MaxThreads > 0 && Environment.ProcessorCount > PipelineConfig.MaxThreads) ? PipelinConfig.MaxThreads - 1 : Environment.ProcessorCount - 1;
if (poolSize < 0) poolSize = 0;And then following the logic of that ternary statement
MaxThreads is greater than 0 meaning 1 or more and ProcessorCount has to be greater than MaxThreads, so you could get rid of this:if (poolSize < 0) poolSize = 0;but, I think there will be issues. What if
PipelineConfig.MaxThreads is the same as Environment.ProcessorCount ?Code Snippets
private static void InitThreadPool() {
int numLogicalCores = Environment.ProcessorCount;
int poolSize = numLogicalCores;
if (PipelineConfig.MaxThreads > 0 && numLogicalCores > PipelineConfig.MaxThreads) poolSize = PipelineConfig.MaxThreads;
// One less than the number of cores because the master thread will be used too
poolSize -= 1;
if (poolSize < 0) poolSize = 0;
threadPool = new Thread[poolSize];
for (int i = 0; i < poolSize; i++) {
threadPool[i] = new Thread(ThreadWaitForWork) {
Name = "OphSlave-" + i,
IsBackground = true
};
threadPool[i].Start();
}
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
Thread.CurrentThread.Name = "OphMaster";
}private static Thread[] threadPool;private static Thread[] threads;// One less than the number of cores because the master thread will be used too
int poolSize = (PipelineConfig.MaxThreads > 0 && Environment.ProcessorCount > PipelineConfig.MaxThreads) ? PipelinConfig.MaxThreads - 1 : Environment.ProcessorCount - 1;
if (poolSize < 0) poolSize = 0;if (poolSize < 0) poolSize = 0;Context
StackExchange Code Review Q#38604, answer score: 3
Revisions (0)
No revisions yet.