Is quit() still the proper way to force exit?


#1

Is quit() still the proper way to force an app to exit? Running cinder master from git on Win10 x64, the following code should exit in a few different spots, but instead continues to execute:

> void IPCServerApp::setup()
> {
> 	TCHAR mFileName[] = TEXT("Global\\MappedObject");
> 	TCHAR mFileMsg[] = TEXT("Sharing Is Caring!");

> 	mFileOpen = false;
> 	mMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, mFileName);
> 	if (mMapFile == NULL)
> 		quit(); // should exit here, mMapFile is NULL
> 	console() << "Memory mapped for share" << endl;

> 	mMapBuffer = (LPTSTR)MapViewOfFile(mMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
> 	auto check = mMapBuffer == NULL;
> 	if (mMapBuffer == NULL) {
> 		CloseHandle(mMapFile);
> 		quit(); // should exit here, mMapBuffer is NULL
> 	}
> 	console() << "Memory view mapped" << endl;

> 	mFileOpen = true;
> 	CopyMemory((PVOID)mMapBuffer, mFileMsg, (_tcslen(mFileMsg)*sizeof(TCHAR))); // CRASH!
> 	console() << "Sharing: " << mFileMsg << endl;
> }

#2

quit() basically requests a polite exit at the next iteration of the application event loop. You probably want to use something like std::exit() or std::abort() if you need immediate termination.

-Andrew


#3

Something I’ve always found strange about calling quit() is that it doesn’t actually do anything until it receives a subsequent app (e.g. UI) event… For example, if I call quit() in the setup() for my program because something failed to start up properly, the update() and draw() methods still get called (and repeatedly). The program actually only exits once I move the mouse or press a key. This is with Cinder 0.9.0 on OS X. Is it supposed to work that way? I thought it would send a quit to the message loop, which (if I’ve done nothing else) should be one of the next things to be processed.


#4

Oops, sorry for the noise, I should have searched first… I found this issue should be dealt with for the next release: https://github.com/cinder/Cinder/pull/1469 (fixed in May 2016)

Thanks!


#5

@djTomServo @totalgee @andrewfb calling quit() doesn’t close my application - tried calling from update() and on keyDown().

I’m using Windows 10, VS 2013. I’ve tried running the test referenced here: https://github.com/cinder/Cinder/pull/1469 and it works as it’s supposed to.

I’ve also tried calling std:exit(0) and std::abort, but to no avail.

Any suggestions?


#6

quit() flags the application, making it quit at the end of the current frame (not immediately). Any commands that directly follow quit() will therefor still be executed.

Also, if your application uses multiple threads, make sure to terminate them. You can do this in a cleanup() method of your application.

Singletons that use their own thread are notorious for stalling the application indefinitely on exit. The singleton will never be destroyed while the thread is still running. Forcefully terminate any singleton’s thread on cleanup.


#7

Thanks Paul, I’m making use of a threadpool so I’ll try the cleanup() route!


#8

hi @paul.houx I’m not having much luck with the cleanup() method here. I wasn’t sure if I’d need to manage the cleanup process for the entire app myself because I’m overriding the Base App? Trying a mix of calling destructors etc, basically just hacking away, but nothing seems to work. Any thoughts?

Calling quit() on keyEvent:

void MyApp::cleanup()
{
	mCameraManager.StopAndClose();
	mCameraManager.~CameraManager();
	mOscListener.shutdown();
	mSocket->~Socket();
	mThreadpool->close();
	mThreadpool->~ThreadPool();
}

void ThreadPool::close()
{
	if (!mIoService)return;

	if (!mIoService->stopped())
		mIoService->stop();

	for (auto & thread : mThreadPool)
		thread->join();

	mThreadPool.clear();
	mIoService = nullptr;
	mWork = nullptr;
}

#9

This doesn’t solve your problem but unless you’re using placement new or some other exotic allocation system you shouldn’t be explicitly calling destructors like that.


#10

Often it is not enough to simply join() a thread and hope it will stop running. You should notify the thread that it should quit, so that it can exit its loop. One way to do this is, omitting most of the code:

bool mRunning = true;

void thread()
{
    while( mRunning )
    {
        // ... do stuff...
        // ...and make sure not to stall the CPU
        std::this_thread::sleep_for( std::chrono::milliseconds(1) );
    }
}

void stop() 
{
    // Let the thread exit its loop.
    mRunning = false;

    // Wait for it to end.
    if( mThread.joinable() )
        mThread.join();
}

#11

Thanks @lithium.snepo, i’ll keep that in mind


#12

Thanks @paul.houx I’ll give that a try