How to properly manage messages sent to a thread in C++ - c++

In my Android app, I use C++ to do some work. In my C++ code, I use a thread to do some tasks. Using this example and this example, here is how I proceed (I simplified the actual code to keep it easy to read):
std::thread* threadLocal;
std::queue<ThreadMessage*> queueLocale;
std::mutex mutexLocal;
std::condition_variable cvLocal;
struct ThreadMessage
{
ThreadMessage(int i)
{
id = i;
}
int id;
};
void MyWorkerThread::createThread()
{
if (!threadLocal)
{
threadLocal = new std::thread(&MyWorkerThread::process, this);
}
}
void MyWorkerThread::sendTask1()
{
if (threadLocal)
{
// message:
ThreadMessage* threadMessage = new ThreadMessage(MSG_TASK_1);
// send the message:
std::unique_lock<std::mutex> lock(mutexLocal);
queueLocale.push(std::move(threadMessage));
cvLocal.notify_one();
}
}
void MyWorkerThread::sendTask2()
{
if (threadLocal)
{
// message:
ThreadMessage* threadMessage = new ThreadMessage(MSG_TASK_2);
// send the message:
std::unique_lock<std::mutex> lock(mutexLocal);
queueLocale.push(std::move(threadMessage));
cvLocal.notify_one();
}
}
void MyWorkerThread::process()
{
while (1)
{
// init :
ThreadMessage* threadMessage = 0;
// waiting for messages :
{
std::unique_lock<std::mutex> lock(mutexLocal);
while (queueLocale.empty())
{
cvLocal.wait(lock);
}
threadMessage = std::move(queueLocale.front());
queueLocale.pop();
}
// tasks :
switch (threadMessage->id)
{
case MSG_TASK_1:
{
doSomeWork1();
delete threadMessage;
break;
}
case MSG_TASK_2:
{
doSomeWork2();
delete threadMessage;
break;
}
default:
{
delete threadMessage;
break;
}
}
}
}
It works well in most cases, but sometimes, my app crashes when a delete threadMessage is called, and I don't understand why (since I don't see how it can be called twice on a same object).
Here are the reasons why I need to send messages to a thread, instead of just creating new threads each time I want to run doSomeWork1() or doSomeWork2():
The doSomeWork1() and doSomeWork2() functions have to be executed in the same thread
One of those functions is very frequently called (approx. 200 times / sec), so I don't want to create a thread each time
So my question is: what is the proper way to send a message to a thread, and manage it inside the thread, to avoid error on the delete?
Thanks for your help.

Related

Modify data inside thread

I am writing unit tests for one of the classes I want to test. Function infFooLoop() what I want to test is executed in endless loop (request to stop it comes externally). My problem is I want to change the private variable state_ via setter in setState when function executes in separate thread asynchronously. Some simplified code example is here:
enum class State : int
{
Success = 1,
Failure = 2
};
class Foo
{
private:
State state_{State::Success};
bool stop_flag_{false};
public:
void setState(State state) { state_ = state; }
void infFooLoop(bool &start)
{
while (start)
{
std::cout << "While loop executes \n";
if (state_ == State::Failure)
{
stop_flag_ = true;
}
else if (stop_flag_)
{
std::cout << "Program stopped\n";
// Report error but for this example break
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
};
int main()
{
Foo obj;
bool flag{true};
std::future<void> future = std::async(std::launch::async, [&](){ obj.infFooLoop(flag);});
// Try to change the data:
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// I want to change data for `Failure` so stop_flag condition will be used
obj.setState(State::Failure);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// terminate loop
flag = false;
return 0;
}
state_ will be taken from external component and stop_flag_ is used to handle some corner-case here (in real it wont break the loop, just report error to different component).
I assume infFooLoop executes on a separate thread so I can't just call another function in a different thread to change this data. stop_flag_ is some internal variable used only in this one function so I want to leave it as simple as possible (do not introduce mutexes/atomic in Foo class only for tests). Can you give me some suggestions on what should I do here?

In Unreal C++ why are structs added to a TArray in an async thread not removed from RAM?

I am asking this question from an Unreal Engine C++ code point of view but I am wondering if my problem is more to do with the nuances of C++'s way of operating.
I have a Unreal actor. A simple class that holds an array of my own structs and runs a timer which triggers my own function. This function passes a reference of the actors array to an asynchronous task.
This async task then goes to work, first creating a new struct, then adding two floats to its own internal TArray of floats and then adds that struct to the main actors array.
The problem:
After the async task has completed and I delete the actor from the level editor window, the system RAM is decreased as I call the Empty() function on the main actors array in the Destroyed() function but the RAM used by all of the structs (ie: The float array inside each struct) is left in memory and never cleared out.
Observations:
If I do not use an async task and run the same function inside the main thread ALL of the memory is cleared successfully.
If I do not create the struct inside the async task and instead initalize the array with a load of structs which in turn are initialized with N number of floats inside the main thread, then pass that as a reference to the async task which works on the data, then the memory is also cleared out successfully.
What I would like to happen
I would like to pass a reference of the main actors array of structs to the async task. The async task would then go to work creating the data. Once it is complete, the main actor would then have access to the data and when the actor is deleted in the level editor window, ALL of the memory would be freed.
The code:
The definition of the data struct I am using:
struct FMyDataStruct
{
TArray<float> ArrayOfFloats;
FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
FMyDataStruct(int32 FloatCount)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
~FMyDataStruct()
{
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
};
The main actors definition of the array I am using:
TArray<FMyDataStruct> MyMainArray;
The main actors custom function I am running:
//CODE 1: This part DOES empty the RAM when run (ie: Run on main thread)
/*for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}*/
//CODE 2: This does NOT empty the RAM when run. The two floats * 50,000,000 are left in system memory after the actor is deleted.
auto Result = Async(EAsyncExecution::Thread, [&]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyDataStruct.ArrayOfFloats.Add(FMath::Rand());
MyMainArray.Add(MyDataStruct);
}
});
An example of initializing the array in the main thread, then working on it inside the async task:
//Initialize the array and its structs (plus the float array inside the struct)
MyMainArray.Init(FMyDataStruct(2), 50000000);
//TFuture/Async task
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
//Call the main threads task completed function
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->MyTaskComplete();
}
});
});
Final thoughts:
Ultimately what I am asking is can anyone explain to me why from a C++ point of view the structs and their data would be removed from memory successfully when created/added from the main thread but then not removed from memory if created inside the async task/thread?
Update #1:
Here is a minimum reproducible example:
Create a new project in either Unreal Engine 4.23, 4.24 or 4.25.
Add a new C++ actor to the project and name it "MyActor".
Edit the source with the following:
MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
struct FMyDataStruct
{
FMyDataStruct()
{
//Default Constructor
}
FMyDataStruct(const FMyDataStruct& other)
: ArrayOfFloats(other.ArrayOfFloats)
{
//Copy constructor
}
FMyDataStruct(FMyDataStruct&& other)
{
//Move constructor
if (this != &other)
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
}
FMyDataStruct& operator=(const FMyDataStruct& other)
{
//Copy assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = other.ArrayOfFloats; //UE4 TArray deep copy
}
return *this;
}
FMyDataStruct& operator=(FMyDataStruct&& other)
{
//Move assignment operator
if (this != &other) //avoid self assignment
{
ArrayOfFloats = MoveTemp(other.ArrayOfFloats);
}
return *this;
}
FMyDataStruct(int32 FloatCount)
{
//Custom constructor to initialize the float array
if (FloatCount > 0)
{
ArrayOfFloats.Init(0.f, FloatCount);
}
}
~FMyDataStruct()
{
//Destructor
ArrayOfFloats.Empty();
ArrayOfFloats.Shrink();
}
public:
TArray<float> ArrayOfFloats;
};
UCLASS()
class BASICPROJECT1_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
protected:
virtual void Destroyed() override;
public:
bool IsEditorOnly() const override;
bool ShouldTickIfViewportsOnly() const override;
virtual void Tick(float DeltaTime) override;
void DoSomething();
void AsyncTaskComplete();
bool bShouldCount = true;
float TimeCounter = 0.f;
TArray<FMyDataStruct> MyMainArray;
};
MyActor.cpp
#include "MyActor.h"
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
}
void AMyActor::Tick(float DeltaTime)
{
if (!HasAnyFlags(RF_ClassDefaultObject)) //Check for not CDO. We only want to run in the instance
{
if (bShouldCount)
{
TimeCounter += DeltaTime;
if (TimeCounter >= 5.f)
{
bShouldCount = false;
DoSomething();
}
}
}
}
void AMyActor::Destroyed()
{
Super::Destroyed();
MyMainArray.Empty();
MyMainArray.Shrink();
UE_LOG(LogTemp, Warning, TEXT("Actor got Destroyed!"));
}
bool AMyActor::IsEditorOnly() const
{
return true;
}
bool AMyActor::ShouldTickIfViewportsOnly() const
{
return true;
}
void AMyActor::DoSomething()
{
//Change the code that is run:
//1 = Main thread only
//2 = Async only
//3 = Init on main thread and process in async task
//======================
int32 CODE_SAMPLE = 1;
UE_LOG(LogTemp, Warning, TEXT("Actor is running DoSomething()"));
TWeakObjectPtr<AMyActor> Self = this;
if (CODE_SAMPLE == 1)
{
//CODE 1: Run on main thread. This part DOES empty the RAM when run. BLOCKS the editor window.
//=========================================================================
MyMainArray.Empty();
MyMainArray.Shrink();
MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyMainArray.Emplace(MyDataStruct);
}
UE_LOG(LogTemp, Warning, TEXT("Main thread array fill is complete!"));
}
else if (CODE_SAMPLE == 2)
{
//CODE 2: Run on async task. This does NOT empty the RAM when run
//(4 bytes per float * 2 floats * 50,000,000 structs = 400Mb is left in system memory after the actor is deleted)
//=========================================================================
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
Self->MyMainArray.Empty();
Self->MyMainArray.Shrink();
Self->MyMainArray.Reserve(50000000);
for (int32 Index = 0; Index < 50000000; Index++)
{
FMyDataStruct MyDataStruct;
MyDataStruct.ArrayOfFloats.Reserve(2);
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
MyDataStruct.ArrayOfFloats.Emplace(FMath::Rand());
Self->MyMainArray.Emplace(MyDataStruct);
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
else if (CODE_SAMPLE == 3)
{
//CODE 3: Initialize the array in the main thread and work on the data in the async task
//=========================================================================
MyMainArray.Init(FMyDataStruct(2), 50000000);
auto Result = Async(EAsyncExecution::Thread, [Self]()
{
if (Self != nullptr)
{
for (int32 Index = 0; Index < 50000000; Index++)
{
Self->MyMainArray[Index].ArrayOfFloats[0] = FMath::Rand();
Self->MyMainArray[Index].ArrayOfFloats[1] = FMath::Rand();
}
AsyncTask(ENamedThreads::GameThread, [Self]()
{
if (Self != nullptr)
{
Self->AsyncTaskComplete();
}
});
}
});
}
}
void AMyActor::AsyncTaskComplete()
{
UE_LOG(LogTemp, Warning, TEXT("Async task is complete!"));
}
Compile and run the project.
Drag the actor into the level editor window.
After 5 seconds the code will run and the RAM usage will increase to 1750Mb.
Select the actor in the outliner window and delete it.
The RAM usage will perform like this:
CODE 1: RAM is cleared out all the way to the starting RAM usage of 650Mb.
CODE 2: RAM is cleared down to 1000Mb and never returns to starting usage.
CODE 3: RAM is cleared out all the way to the starting RAM usage of 650Mb.
I thank you for your help.

std::list::empty() returns true even though list is filled

I am having issues in a code having structure similar to the following minimum example. There is only one instance of MainClass. It makes new instance of Classlet on each call to its MainClass::makeclasslet()
I have multiple classlets writing to a single list buffer. After some time I need to copy/ dump the values from list buffer (FIFO).
The problem is that I am getting the following output in MainClass::clearbuffer()
>>>>>>>>>> 704 >>>>>>>>>>>>>>>>>>> Buffer size: 65363..... 1
I am unable to understand why the std::list::empty() returns true even when the buffer is locked with an atomic bool flag.
I have tried moving the call to clearbuffer() (in addval()) to the main application thread so that not each Classlet event calls clearbuffer().
I have also tried adding delay QThread::msleep(10); after setting busy = true;.
But some time after the application starts, I am getting the output shown above. Instead of popping all 65363+704 values in the list, it only popped 704 and broke the loop on list::isempty() being true (apparently).
class MainClass : public QObject {
Q_OBJECT
private:
std:: list<int> alist;
std::atomic<bool> busy;
MainClass() {
busy = false;
}
~MainClass() {
// delete all classlets
}
void makeclasslet() {
Classlet newclasslet = new Classlet();
// store the reference
}
void addval(int val) {
alist.push_back(val);
if (alist.size() > 100)
{
if (!busy)
{
clearbuffer();
}
}
}
void clearbuffer() {
if (!busy)
{
busy = true;
int i = 0;
while (!alist.empty())
{
i = i + 1;
// save alist.front() to file
alist.pop_front();
}
printf(">>>>>>>>>> %d >>>>>>>>>>> Buffer size: %d ..... %d\n", i, m_lstCSVBuffer.size(), m_lstCSVBuffer.empty());
busy = false;
}
}
}
class Classlet {
private:
Mainclass* parent;
void onsomeevent(int val) {
parent->addval(val);
}
}
I am using qt5.9 on Ubuntu 18.04. GCC/ G++ 7.5.0

Deadlock in C++ code

I try to handle a deadlock in my code but I can't fugure out how to prevent it. I have a thread which accesses data and an update method which update the data. The code looks like this:
thread {
forever {
if (Running) {
LOCK
access data
UNLOCK
}
Running = false;
}
}
update {
Running = false;
LOCK
access data
UNLOCK
Running = true;
}
I tried to fix it with a second access variable but it doesn't change anything.
thread {
forever {
if (!Updating) {
if (Running) {
LOCK
access data
UNLOCK
}
}
Running = false;
}
}
update {
Updating = true;
Running = false;
LOCK
access data
UNLOCK
Updating = false;
Running = true;
}
Thanks for your help.
UPDATE
This is a better description of the problem:
thread {
forever {
if (Running) {
LOCK
if (!Running) leave
access data
UNLOCK
}
Running = false;
}
}
update {
Running = false;
LOCK
access data
UNLOCK
Running = true;
}
My update function is a bit more complex, so that I can't see a way to use one of the standard algorithm for this.
UPDATE 2
Here is the simplified c++ source code. maybe it's better to read as the pseudocode:
void run() {
forever {
if (mRunning) {
QMutexLocker locker(&mMutex);
for (int i; i < 10; i++) {
qDebug("run %d", i);
sleep(1);
if (!mRunning) break;
}
mRunning = false;
}
}
}
void update() {
mRunning = false;
QMutexLocker locker(&mMutex);
qDebug("update");
mRunning = true;
}
UPDATE 3
Ok. The problem is a bit more complex. I forgot that my accesss data part in the thread starts also some child threads to fill the data structure
datathread {
access data
}
thread {
forever {
if (Running) {
LOCK
if (!Running) leave
forloop
start datathread to fill data to accessdata list
UNLOCK
}
Running = false;
}
}
update {
Running = false;
LOCK
access data
UNLOCK
Running = true;
}
Standard way for read method being restarted when during write is to use seqlock. With single writer and reader seqlock is just atomic integer variable, which is incremented every time when writer is started and when it is ended. Such a way reader method can periodically check whether variable is unchanged since read is started:
atomic<int> seq = 0;
updater() // *writer*
{
seq = seq + 1;
<update data>
seq = seq + 1;
}
thread() // *reader*
{
retry: // Start point of unmodified data processing.
{
int seq_old = seq;
if(seq_old & 1)
{
// odd value of the counter means that updater is in progress
goto retry;
}
for(int i = 0; i < 10; i++)
{
<process data[i]>
if(seq_old != seq)
{
// updater has been started. Restart processing.
goto retry;
}
}
// Data processing is done.
}
}
If several updater() can be executed concurrently, whole update code should be executed with mutex taken:
updater() // *writer*
{
QMutexLocker locker(&updater_Mutex);
seq = seq + 1;
<update data>
seq = seq + 1;
}
If even single element of data cannot be accessed concurrently with updating, both <update data> and <process data[i]> should be executed with mutex taken.

RxCpp: how to control subject observer's lifetime when used with buffer_with_time

The purpose of the following code is to have various classes publish data to an observable. Some classes will observe every data, some will observe periodically with buffer_with_time().
This works well until the program exits, then it crashes, probably because the observer using buffer_with_time() is still hanging on to some thread.
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { _subscriber.on_completed(); }
void publish(std::string data) { _subscriber.on_next(data); }
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo()
{
Data data;
auto period = std::chrono::milliseconds(30);
auto s1 = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.subscribe([](std::vector<std::string>& data)
{ std::cout << data.size() << std::endl; });
data.publish("test 1");
data.publish("test 2");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
I tried calling "s1.unsubscribe()", and various as_blocking(), from(), merge(), but still can't get the program to exit gracefully.
Note that I used "subjects" here because "publish" can then be called from different places (which can be from different threads). I am not sure if this is the best mechanism to do that, I am open to other ways to accomplish that.
Advice?
This is very close to working..
However, having the Data destructor complete the input while also wanting the subscription to block the exit of foo until input is completed makes this more complex.
Here is a way to ensure that foo blocks after Data destructs. This is using the existing Data contract.
void foo1()
{
rxcpp::observable<std::vector<std::string>> buffered;
{
Data data;
auto period = std::chrono::milliseconds(30);
buffered = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.publish().ref_count();
buffered
.subscribe([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
data.publish("test 1");
data.publish("test 2");
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
buffered.as_blocking().subscribe();
printf("exit foo1\n");
}
Alternatively, the changing the shape of Data (add a complete method) would allow the following code:
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { complete(); }
void publish(std::string data) { _subscriber.on_next(data); }
void complete() {_subscriber.on_completed();}
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo2()
{
printf("foo2\n");
Data data;
auto newthread = rxcpp::observe_on_new_thread();
auto period = std::chrono::milliseconds(30);
auto buffered = data.observable()
.buffer_with_time(period , newthread)
.tap([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
auto emitter = rxcpp::sources::timer(std::chrono::milliseconds(0), newthread)
.tap([&](long) {
data.publish("test 1");
data.publish("test 2");
data.complete();
});
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
buffered.combine_latest(newthread, emitter).as_blocking().subscribe();
printf("exit foo2\n");
}
I think that this better expresses the dependencies..