FCriticalSection doesn't unlock - What am i doing wrong?

Hey (this is my first post), i am tesing some multithreading in unreal engine with the help of Ramas Tutorial about multithreading and was asking myself how synchronization would work with the unreal engine thread classes.

So, i was trying to use FCriticalSection… but i don’t get it work properly… FCriticalSection::TryLock() alwas returns false after it was unlocked from the destructor of FScopeLock.

What am I doing? I create 2 instances of the class below if i press a button in the game. Thread 1 does his work immediately (calculating some prime numbers and stop thread 2 from doing the same) and thread 2 waits for an unlocked FCriticalSection but stucks in his wait loop forever. NOW, why is going to be an infinite loop? I also tried it with 2 threads inside 1 instance of the class and with FCriticalSection as member variable instead of a static class variable - but without any changes.

That’s the class I’m working with:

.H FILE:

class FExampleThreadWorker : public FRunnable
{
public:
	FExampleThreadWorker();
	~FExampleThreadWorker();

	//Begin FRunnable Methods
	bool Init() override;
	uint32 Run() override;
	void Stop() override;
	//End

protected:
	/** Thread to run the worker FRunnable on */
	FRunnableThread* Thread;
	static FCriticalSection critical;

	int workerNumber;
	static int workerCount;
};

.CPP FILE

int FExampleThreadWorker::workerCount = 0; 
FCriticalSection FExampleThreadWorker::critical;

FExampleThreadWorker::FExampleThreadWorker()
{
	workerNumber = ++workerCount;
	FString name("FExampleThreadWorker");
	name.AppendInt(workerNumber);
	Thread = FRunnableThread::Create(this, *name, 0, TPri_Normal);
	if (!Thread)
		GLog->Log("Failed to create FExampleThreadWorker Thread!");	
}

FExampleThreadWorker::~FExampleThreadWorker()
{
	delete Thread;
	Thread = nullptr;
	--workerCount;
}

bool FExampleThreadWorker::Init()
{
	return true;
}

uint32 FExampleThreadWorker::Run()
{
	//Initial wait before starting
	FPlatformProcess::Sleep(0.03f);

	//wait until unlocked
	while (!critical.TryLock());

	//locked scope
	{
		FScopeLock lock(&critical);
		GLog->Log("Thread " + FString::FromInt(workerNumber) + " start locked work");

		//some prime number calculation
		int32 TestPrime = 2;
		int32 primesFoundCount = 0;
		bool NumIsPrime = false;

		while (primesFoundCount <= 20000)
		{
			NumIsPrime = true;
			TestPrime++;

			for (int32 b = 2; b < TestPrime; b++)
			{
				if (TestPrime % b == 0)
				{
					NumIsPrime = false;
					break;
				}
			}
			if (NumIsPrime)
				++primesFoundCount;
		}

		GLog->Log("Thread " + FString::FromInt(workerNumber) + " finished locked work");
	}
	
	return 0;
}

void FExampleThreadWorker::Stop() { }

Maybe there’s another and easier way of doing this… I hope anyone can help me with this issue or suggest a better solution for thread synchronization in unreal engine.

Thanks in advance for your help! :slight_smile:

Bernhard

You shouldn’t need the “while(!critical.TryLock())” statement at all, the FScopeLock will take care of all the locking/unlocking for you.

Oh yeah you are right, thank you, this is what i was looking for - the synchronization works wonderful!

But neverthless, i really would like to know why FCriticalSection::TryLock() returns false even if i unlock the critical section?

Whoops! Thats good to know - thanks for the quick answer :slight_smile:

TryLock actually does perform a lock under the hood and then you never unlock it (the ScopeLock would try to lock it as well). You have mismatched lock/unlock which can cause the issue you are seeing.