I have c++ console an application that looks something like this:
SomeObj* obj;
BOOL WINAPI closeHandler(DWORD cEvent)
{
obj->Stop();
while( obj != 0 )
{
Sleep(100);
}
return TRUE;
}
int main(int argc, char* argv[])
{
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)SignalHandler, true );
obj = new SomeObj();
obj->Execute();
delete obj;
return 0;
}
SomeObj::Execute() is essentially a loop that keeps running until SomeObj::Stop() is called. When I do a CTRL+C, I can see that the application deletes obj properly before exiting. However, when I click on the close button on the console window, I find out that obj doesn't get deleted properly.
Further debugging showed that closeHandler is actually called, but somehow obj just doesn't get deleted. Strangely, if I put a breakpoint on the return 0 line and try to close the console window, I end up hitting that breakpoint and see that obj was deleted.
What am I doing wrong here? Is there a better way to deallocate stuff on a console window close event?
I'm guessing your closeHandler() routine never actually completes because it is waiting for obj to become 0 (presumably you mean "NULL" or C++11-style "nullptr" here). Deleting an object does not set pointers to it to null. I'm honestly not sure why it has this loop at all?
Yes, there is a way that doesn't require you to manually call delete or set the pointer to null. Use a smart pointer like std::unique_ptr. You also don't have to wait for the object to be deleted since cleanup will be handled properly once Execute finishes and main returns.
#include <iostream>
#include <memory>
// sample test object that oeprates as described in your question.
struct Object
{
Object() : running_(true) {}
~Object()
{
std::cout << "Object deleted" << std::endl;
}
void Stop() { running_ = false; }
void Execute() { while(running_ == true); }
bool running_;
};
// incredibly smart pointer!
std::unique_ptr<Object> obj;
BOOL WINAPI closeHandler(DWORD)
{
// We need to call stop on the object if it exists
// use appropriate locks for multithreaded environment
if(obj != nullptr)
{
obj->Stop();
// no need to wait
}
return TRUE;
}
int main()
{
SetConsoleCtrlHandler( closeHandler, true );
// Allocate the object and execute
obj.reset(new Object());
obj->Execute();
}
I would suggest that your handler isn't actually deleting the object. You specify obj as a global but do not actually delete it in the closeHandler. Maybe something like the following...
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
if (CTRL_CLOSE_EVENT == dwCtrlType)
{
if (NULL != obj)
{
delete obj;
obj = NULL
}
}
}
Related
I am developing a serial port program using boost::asio.
In synchronous mode I create a thread every time read_sync function is called. All reading related operation are carried in this thread (implementation is in read_sync_impl function).
On close_port or stop_read function reading operation is stopped.
This stopped reading operation can be restarted by calling the read_sync function again.
read_sync function will never be called successively without calling close_port or stop_read function in between.
I wish to know how to implement a class wide std::jthread along with proper destructor when I call my read_sync function. In languages like Kotlin or Dart the garbage-collector takes care of this. What is C++ implementation of this.
bool SerialPort::read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
this->thread_sync_read = std::jthread(&SerialPort::read_sync_impl, this);
return true;
}
bool SerialPort::read_sync_impl(const std::stop_token& st)
{
while(true)
{
...
if (st.stop_requested())
{
PLOG_INFO << "Stop Requested. Exiting thread.";
break;
}
}
}
bool SerialPort::close_port(void)
{
this->thread_sync_read->request_stop();
this->thread_sync_read->join();
this->port.close();
return this->port.is_open();
}
class SerialPort
{
public :
std::jthread *thread_sync_read = nullptr;
...
}
Actual Code
bool SerialPort::read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
try
{
if (read_timeout not_eq ignore_read_timeout)
this->read_timeout = read_timeout;//If read_timeout is not set to ignore_read_timeout, update the read_timeout else use old read_timeout
if (this->thread_sync_read.joinable())
return false; // Thread is already running
thread_sync_read = std::jthread(&SerialPort::read_sync_impl, this);
return true;
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
return false;
}
}
void SerialPort::read_sync_impl(const std::stop_token& st)
{
try
{
while (true)
{
if (st.stop_requested())
{
PLOG_INFO << "Stop Requested in SerialPort::read_sync_impl. Exiting thread.";
break;
}
}
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
}
}
class SerialPort
{
std::jthread thread_sync_read;
SerialPort() : io(), port(io), thread_sync_read()
{
read_buffer.fill(std::byte(0));
write_buffer.fill(std::byte(0));
}
}
You don't need to deal with the jthread's destructor. A thread object constructed without constructor arguments (default constructor), or one that has been joined, is in an empty state. This can act as a stand-in for your nullptr.
class SerialPort
{
public :
std::jthread thread_sync_read;
...
SerialPort(...)
: thread_sync_read() // no explicit constructor call needed, just for show
{}
SerialPort(SerialPort&&) = delete; // see side notes below
SerialPort& operator=(SerialPort&&) = delete;
~SerialPort()
{
if(thread_sync_read.joinable())
close_port();
}
bool read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
if(thread_sync_read.joinable())
return false; // already reading
/* start via lambda to work around parameter resolution
* issues when using member function pointer
*/
thread_sync_read = std::jthread(
[this](const std::stop_token& st) mutable {
return read_sync_impl(st);
}
);
return true;
}
bool close_port()
{
thread_sync_read.request_stop();
thread_sync_read.join(); // after this will be back in empty state
port.close();
return port.is_open();
}
};
Side notes
Starting and stopping threads is rather expensive. Normally you would want to keep a single worker thread alive and feed it new read/write requests via a work queue or something like that. But there is nothing wrong with using a simpler design like yours, especially when starting and stopping are rare operations
In the code above I delete the move constructor and assignment operator. The reason is that the thread captures the this pointer. Moving the SerialPort while the thread runs would lead to it accessing a dangling pointer
You're already reinitialize (move new one into) thread_sync_read in SerialPort::read_sync, everything should works.
at destructor, you need to remember delete read_sync
SerialPort::~SerialPort(){
close_port(); // if necessary to close port
delete thread_sync_read;
}
or if you declare thread_sync_read not as (raw) pointer
class SerialPort{
public:
std::jthread thread_sync_read;
}
then you don't need to delete it.
SerialPort::~SerialPort(){
close_port(); // if necessary
}
note that the destructor of std::jthread would perform necessary request_stop() and join() by itself.
I try to explain my problem with a simple example
typedef function<bool()> TaskCallback;
class Task
{
public:
Task(TaskCallback task_callback) : task_callback(task_callback)
{
long_string_test = "This is a long string 0123456789ABCDEF 0123456789ABCDEF 0123456789ABCDEF";
xTaskCreate(Task::RunTask, "task_name", 2560, this, 3, &task_handle);
}
~Task()
{
while(1); //Breakpoint: The destructor is never called
}
private:
static void RunTask(void* params)
{
Task* _this = static_cast<Task*>(params);
_this->task_callback(); //The program crashes here because task_callback doesn't exist
}
string long_string_test;
TaskCallback task_callback;
TaskHandle_t task_handle;
};
main.cpp
static bool Init_task() { }
void main()
{
Task task(Init_task);
vTaskStartScheduler();
//We should never get here as control is now taken by the FreeRTOS scheduler
while(1);
}
If I check the value of the string long_string_test through the debbuger in the RunTask function I find that it has a strange value, as if the string had been destroyed.
But the destructor of Task class was never called.
If I change the "main.cpp" as below the program works correctly, I think the compiler does some sort of optimization:
static bool Init_task() { }
Task task(Init_task);
void main()
{
vTaskStartScheduler();
//We should never get here as control is now taken by the FreeRTOS scheduler
while(1);
}
p.s. obviously compiler optimizations are disabled
As part of the vTaskStartScheduler call, prvPortStartFirstTask will reset the stack pointer. I can imagine that this will eventually cause other code to overwrite parts of the Task object on the discarded stack space allocated for main. You could set a data breakpoint with the debugger, but I would consider the main stack space trashed when the first task starts.
I think the best solution here is indeed to allocate the Task object statically or possibly with a heap allocation (if your system allows it).
#Botje You're right I changed my example to verify what you said.
main.cpp
int* test;
static void RunTask(void* params)
{
Print(*test); //The "test" pointer has a random value
}
void main()
{
int temp = 9999;
test = &temp;
xTaskCreate(RunTask, "task_name", 2560, NULL, 3, NULL);
vTaskStartScheduler(); //It seems that FreeRTOS clears the main() stack
//We should never get here as control is now taken by the FreeRTOS scheduler
while(1);
}
I have a scenario where:
I launch a new thread from within a dll that does some work.
The dlls destructor could be called before the new thread finishes its work.
If so I want to set a boolean flag in the destructor to tell the thread to return and not continue.
If I try the following then I find that because the destructor is called and MyDll goes out of scope then m_cancel is deleted and its value is unreliable (Sometimes false, sometimes true) so I cannot use this method.
Method 1
//member variable declared in header file
bool m_cancel = false;
MyDll:~MyDll()
{
m_cancel = true;
}
//Function to start receiving data asynchronously
void MyDll::GetDataSync()
{
std::thread([&]()
{
SomeFunctionThatCouldTakeAWhile();
if( m_cancel == true )
return;
SomeFunctionThatDoesSomethingElse();
}
}
So I have looked at this example Replacing std::async with own version but where should std::promise live? where a shared pointer is used which can be accessed from both threads.
So I was thinking that I should:
Create a shared pointer to a bool and pass it to the new thread that I have kicked off.
In the destructor, change the value of this shared pointer and check it in the new thread.
Here is what I have come up with but I'm not sure if this is the proper way to solve this problem.
Method 2
//member variable declared in header file
std::shared_ptr<bool> m_Cancel;
//Constructor
MyDll:MyDll()
{
m_Cancel = make_shared<bool>(false);
}
//Destructor
MyDll:~MyDll()
{
std::shared_ptr<bool> m_cancelTrue = make_shared<bool>(true);
m_Cancel = std::move(m_cancelTrue);
}
//Function to start receiving data asynchronously
void MyDll::GetDataSync()
{
std::thread([&]()
{
SomeFunctionThatCouldTakeAWhile();
if( *m_Cancel.get() == true )
return;
SomeFunctionThatDoesSomethingElse();
}
}
If I do the above then the if( *m_Cancel.get() == true ) causes a crash (Access violation)
Do I pass the shared pointer by value or by reference to the std::thread??
Because its a shared pointer, will the copy that the std::thread had still be valid even MyDll goes out of scope??
How can I do this??
Method 3
//Members declared in header file
std::shared_ptr<std::atomic<bool>> m_Cancel;
//Constructor
MyDll:MyDll()
{
//Initialise m_Cancel to false
m_Cancel = make_shared<std::atomic<bool>>(false);
}
//Destructor
MyDll:~MyDll()
{
//Set m_Cancel to true
std::shared_ptr<std::atomic<bool>> m_cancelTrue = make_shared<std::atomic<bool>>(true);
m_Cancel = std::move(m_cancelTrue);
}
//Function to start receiving data asynchronously
void MyDll::GetDataSync()
{
std::thread([=]() //Pass variables by value
{
SomeFunctionThatCouldTakeAWhile();
if( *m_Cancel.get() == true )
return;
SomeFunctionThatDoesSomethingElse();
}
}
What I fund is that when the destructor gets called and then if( *m_Cancel.get() == true ) is called it always crashes.
Am I doing something wrong??
Solution
I have added in a mutex to protect against the dtor returning after cancel has been checked in the new thread.
//Members declared in header file
std::shared_ptr<std::atomic<bool>> m_Cancel;
std::shared_ptr<std::mutex> m_sharedMutex;
//Constructor
MyDll:MyDll()
{
//Initialise m_Cancel to false
m_Cancel = make_shared<std::atomic<bool>>(false);
m_sharedMutex = make_shared<std::mutex>();
}
//Destructor
MyDll:~MyDll()
{
//Set m_Cancel to true
std::shared_ptr<std::atomic<bool>> m_cancelTrue = make_shared<std::atomic<bool>>(true);
std::lock_guard<std::mutex> lock(*m_sharedMutex);//lock access to m_Cancel
{
*m_Cancel = std::move(cancelTrue);
}
}
//Function to start receiving data asynchronously
void MyDll::GetDataSync()
{
auto cancel = this->m_Cancel;
auto mutex = this->m_sharedMutex;
std::thread([=]() //Pass variables by value
{
SomeFunctionThatCouldTakeAWhile();
std::lock_guard<std::mutex> lock(*mutex);//lock access to cancel
{
if( *cancel.get() == true )
return;
SomeFunctionThatDoesSomethingElse();
}
}
}
Step 2 is just wrong. That's a design fault.
Your first mechanism doesn't work for a simple reason. m_cancel==false may be optimized out by the compiler. When the destructor returns, m_cancel ceases to exist, and no statement in the destructor depends on that write. After the destructor returns, it would be Undefined Behavior to access the memory which previously held m_cancel.
The second mechanism (global) fails for a more complex reason. There's the obvious problem that you have only one global m_Cancel (BTW, m_ is a really misleading prefix for something that's not a member). But assuming you only have one MyDll, it can still fail for threading reasons. What you wanted was not a shared_ptr but a std::atomic<bool>. That is safe for access from multiple threads
[edit]
And your third mechanism fails because [=] captures names from the enclosing scope. m_Cancel isn't in that scope, but this is. You don't want a copy of this for the thread though, because this will be destroyed. Solution: auto cancel = this->m_Cancel; std::thread([cancel](...
[edit 2]
I think you really should read up on basics. In the dtor of version 3, you indeed change the value of m_cancel. That is to say, you change the pointer. You should have changed *m_cancel, i.e. what it points to. As I pointed out above, the thread has a copy of the pointer. If you change the original pointer, the thread will continue to point to the old value. (This is unrelated to smart pointers, dumb pointers behave the same).
Somehow, accessing a shared_ptr without dereferencing it is causing a Signal 11 (SIGSEGV) on Android.
I have a run() function in A that acquires a lock for it's instance of B and calls B::top(). There is only one instance of A. A has other public methods that other threads might call to modify mB (thus the mutex), but they are not being called by anything yet.
LogCat Error:
04-17 15:15:16.903: A/libc(11591): Fatal signal 11 (SIGSEGV) at 0x00000024 (code=1)
In class A:
std::thread mControllerThread;
std::mutex mBMutex;
shared_ptr<B> mB;
A() {
mB.reset( new B() );
mControllerThread = std::thread( std::bind(&A::run, this) );
}
//...
void run() {
std::unique_lock<std::mutex > lk(mBMutex);
shared_ptr<const Event> event = mB->top(B::Scope::FUTURE);
}
In class B:
shared_ptr<EventHeap> mFuture;
B() {
mFuture.reset( new EventHeap() );
}
//...
shared_ptr<const Event> top(Scope scope, int mask=EVENT_MASK_SUPPORTED) const {
shared_ptr<const Event> event;
if(scope == Scope::PAST) {
//...
} else if(scope == Scope::FUTURE) {
LOGD(LOG_TAG, "Testing mFuture ptr");
// Fails here with any of these versions
if(mFuture) {
// if(mFuture.get() != NULL) {
// if(mFuture != nullptr) {
LOGD(LOG_TAG, "Getting top from FUTURE");
event = mFuture->top(mask);
} else {
LOGE(LOG_TAG, "mFuture is null");
}
}
return event;
}
So how can accessing a smart pointer without dereferencing it possibly cause a segfault? Thanks!
The statement you point test if the shared_ptr is initialized with a non-null pointer.
if(mFuture) // can be seen as if(mFuture.privateMember_Ptr != nullptr)
It is pretty clear that the pointer itself is not dereferenced, but the value of the pointer is accessed. So this memory location seems invalid. Now where is this memory location? It is part of mFuture which is itself part of B. Let's rewrite the mFuture to show what we really dereference:
if(this->mFuture.privateMember_Ptr != nullptr)
It seems that "this" is invalid, you can start by printing it in the top method, and "unwind" the stack with the same debugging. Looking at the source, "this" should correspond to mB in class A. So you can print mB in A::run() before calling B::top().
mB is initialized in A's ctor with a "new B()". Do you check somewhere that this memory allocation succeed? (exceptions are disabled by default on Android AFAIK, so new can return nullptr)
Let's have the following class definition:
CThread::CThread ()
{
this->hThread = NULL;
this->hThreadId = 0;
this->hMainThread = ::GetCurrentThread ();
this->hMainThreadId = ::GetCurrentThreadId ();
this->Timeout = 2000; //milliseconds
}
CThread::~CThread ()
{
//waiting for the thread to terminate
if (this->hThread) {
if (::WaitForSingleObject (this->hThread, this->Timeout) == WAIT_TIMEOUT)
::TerminateThread (this->hThread, 1);
::CloseHandle (this->hThread);
}
}
//*********************************************************
//working method
//*********************************************************
unsigned long CThread::Process (void* parameter)
{
//a mechanism for terminating thread should be implemented
//not allowing the method to be run from the main thread
if (::GetCurrentThreadId () == this->hMainThreadId)
return 0;
else {
m_pMyPointer = new MyClass(...);
// my class successfully works here in another thread
return 0;
}
}
//*********************************************************
//creates the thread
//*********************************************************
bool CThread::CreateThread ()
{
if (!this->IsCreated ()) {
param* this_param = new param;
this_param->pThread = this;
this->hThread = ::CreateThread (NULL, 0, (unsigned long (__stdcall *)(void *))this->runProcess, (void *)(this_param), 0, &this->hThreadId);
return this->hThread ? true : false;
}
return false;
}
//*********************************************************
//creates the thread
//*********************************************************
int CThread::runProcess (void* Param)
{
CThread* thread;
thread = (CThread*)((param*)Param)->pThread;
delete ((param*)Param);
return thread->Process (0);
}
MyClass* CThread::getMyPointer() {
return m_pMyPointer;
}
In the main program, we have the following:
void main(void) {
CThread thread;
thread.CreateThread();
MyClass* myPointer = thread.getMyPointer();
myPointer->someMethod(); // CRASH, BOOM, BANG!!!!
}
At the moment the myPointer is used ( in the main thread ) it crashes. I don't know how to get the pointer, which points to memory, allocated in another thread. Is this actually possible?
The memory space for your application is accessible to all threads. By default any variable is visible to any thread regardless of context (the only exception would be variables declared __delcspec(thread) )
You are getting a crash due to a race condition. The thread you just created hasn't started running yet at the point where you call getMyPointer. You need to add some kind of synchronization between the newly created thread and the originating thread. In other words, the originating thread has to wait until the new thread signals it that it has created the object.
I'm trying to get my head around what you are trying to do. It looks overly complicated for something like a thread-class. Would you mind post the class-definition as well?
Start by removing the C-style cast of the process-argument to CreateThread():
this->hThread = ::CreateThread (NULL, 0,&runProcess, (void *)(this_param), 0, &this->hThreadId);
If this doesn't compile you're doing something wrong! Never ever cast a function pointer! If the compiler complains you need to change your function, not try to cast away the errors! Really! You'll only make it worse for yourself! If you do it again they* will come to your home and do ... Let's see how you like that! Seriously, don't do it again.
Btw, in Process() I think it would be more appropriate to do something like:
assert(::GetCurrentThreadId() == hThreadId);
But if you declare it private it should only be accessible by your CThread-class anyway and therefor it shouldn't be a problem. Asserts are good though!
*It's not clear who they are but it's clear whatever they do it won't be pleasant!
As Rob Walker pointed out - I really missed the race condition. Also the crash is not when getting the pointer, but when using it.
A simple wait did the job:
MyClass* myPointer = thread.getMyPointer();
while (myPointer == 0)
{
::Sleep(1000);
}
myPointer->someMethod(); // Working :)