Custom thread crash (C++)

Greetings. I created a new thread as FRunnable. Override it’s Init(), Stop(), Exit() functions. When I destroy this thread with Thread->Kill(), I have Stop() called, and next I get an exception that points me to FRunnableThreadWin::Run() on the line with Runnable->Exit(). And the worst thing - this appears sometimes, so I can’t reproduce it on my will.

Hi ,

What version of the Engine are you using, and is it the binary version installed by the Launcher, or did you build the Engine from source code? You mentioned that it seems to be happening intermittently. The next time it happens, could you get the log file for your project and upload it here (you may need to add a .txt extension to the file to be able to upload it)? Does the Engine itself crash when this happens? If so, could you send us a copy of the callstack produced by the crash reporter (if one is created)?

Hi ,
It seems I found how to reproduce. Just create a worker class that extends from FRunnable, override necessary functions - Init(), Run(), Stop(), Exit(). Run() implement like this:

virtual uint32 Run() override
{
	while (!bStop)
	{

	}

	return 0;
};

This bStop will become true in Stop(). Nothing special.
In constructor create a thread:

Thread = FRunnableThread::Create(this, *Name, 0, TPri_BelowNormal, FPlatformAffinity::GetPoolThreadMask());

In destructor kill it:

Thread->Kill();

The killing will call Stop() function and Exit().

Next, somewhere create local instance of our worker - it will be destructed on scope exit. Put a breakpoint in the Stop(). Run it. Depending on your luck you’ll get an exception immediately after breakpoint.

This is just a way to reproduce. In my project I have a class-level worker, After calling Kill() I get an exception. Maybe this is due a delay caused by a breakpoint?

Creating a local thread seams to be a very bad pattern to me, why do you not just handle a pointer over and then create the thread which should not be bound to the current scope, if you want to finish the thread you could then just call kill manually. Or if you require to have the thread in the local scope you should kill it and wait until is it actually done before exiting the local scope.

For an example check how ScreenSaverInhibitorRunnable is setup.

Could it be that the worker gets GC’ed by the engine because of the level change? Is you thread hold by a spawned actor? Also where do you get the exception, in the main thread or in your thread? If its in yours that it seams that the shared memory where the thread is trying to access (the bStop flag for example) is not valid anymore because it has been GC’ed already.

The exception arises in ue class, namely FRunnableThreadWin::Run(). GC? I delete my object manually. One more example - I created a global worker (a pointer). Somewhere initialized it and immediately deleted. My class is absolutely empty so it doesn’t throw. And exception appears more often if I have a breakpoint in Stop() function. But I’m almost sure it can appear without it. But with a breakpoint it’s easier to reproduce.

It can raise in the class, but check the Process window within Visual Studio to see which thread is crashing, this can give us insights on where the error is.

Processes window? There’s only one process - UE4Editor.exe. If you mean threads window, then exception is in my custom thread.

Yes I meant that one :smiley: Sorry for the confusion, then if you get a crash within the windows kernel you are accessing memory that has been already freed. This means that you have to see where you threads gets clear and why the thread is still accessing when it shouldn’t.

I’ll test it this afternoon thanks for sharing the code! :smiley:

Well, that’s exactly my problem. I don’t access it anywhere. Engine does. If you’re to busy to write a test, grab this class FTestWorker : public FRunnable{public: static int count; - Pastebin.com
This is my worker class.
Next, create a global variable

FTestWorker* TestWorker;

Next, in GameState (for example) in constructor add

TestWorker = new FTestWorker{};
delete TestWorker;

And don’t forget to put a breakpoint in Stop() method of the worker. And you can freely investigate.

I did some testing with the code that you provided. I did not see any exceptions thrown, but I did see some significant lag appear in the Editor after starting and stopping my test project several times. I was using version 4.4.3 built from source code.

Did you make a pause with a breakpoint?

Yes. I had set a breakpoint at line 40 of the thread class code you had provide via Pastebin, and an instance of the class was being created and destroyed in the constructor of the GameMode.cpp file in my project. My actual test process was:

  1. Click Play in the Editor.
  2. Click Continue in Visual Studio.
  3. Wait a few seconds.
  4. Click Stop in the Editor.

Then repeat that several times until the Editor began lagging too badly for me to continue (roughly 8-12 repeats).

Can it be OS dependent? I’m using win7. And I have no lags - just crushes.

I am also using , so I don’t believe it is related to OS differences. It is a possibility, though.

What version of the Engine are you currently using? Can you provide the callstack and log after the crash occurs?

Hey -

I just wanted to check if you are still experiencing the crash with the custom thread? If so can you post the callstack and crash log files as well as test in the latest engine version if it is still occurring for you there as well?

Cheers

Hi ,

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will offer further assistance.

Thank you.

When you call Kill(), the thread is still running. Stop() method is supposed to let the thread know that it should stop as soon as possible, but depending on your implementation of Run() the thread may actually never stop. In your case it will stop, but may do it with a certain delay (thread may be suspended at the moment). You don’t however wait for it to stop, instead deleting it instantly. So you’re pulling the rug from under it. The thread wakes up, accesses “this” pointer or sth else and crashes. Simply put, you have to wait for the thread to actually stop before deleting it.