This question is based on the following question: Handle CTRL+C on Win32
I'm working on a multithread server, running on Linux and Windows. I can't use boost or other frameworks, only std c++.
I have a problem with the cleanup code on the win32 side. The linux side is working fine: when I want to shutdown the server, I send SIGINT (with CTRL+C), the signal handler sets a global variable and the main pthread executes the cleanup instructions (joining other pthreads, freeing heap memory, etc.).
On windows it looks not so simple to get the same behavior.
I have written a simple test program to understand how the signal handlers works in windows.
#include <iostream>
#include <windows.h>
bool running;
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv) {
running = true;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
std::cerr << "Error: " << GetLastError() << '\n';
return -1;
}
std::cout << "Main thread working hard...\n";
while (running) { ; }
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return 0;
}
The output is the following:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the 0th fake cleanup instruction
This is the 1th fake cleanup instruction
So the main thread is killed quickly, only after two instruction. In the previous question one of the suggestion was to move the cleanup code in the handler, but is not really helping:
suppose that the handler function looks like this:
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
running = false;
std::cout << "[CTRL+C]\n";
for (int i = 0; i < 20; i++)
std::cout << "This is the " << i << "th fake cleanup instruction\n";
return TRUE;
}
return FALSE;
}
Now the behavior is even worse! The output is:
$ test.exe
Main thread working hard...
[CTRL+C]
This is the
According to MSDN, it seems that the process is always killed:
A HandlerRoutine can perform any necessary cleanup, then take one of
the following actions:
Call the ExitProcess function to terminate the process.
Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.
Return TRUE. In this case, no other handler functions are called and the system terminates
the process.
Am I missing something obvious?
What's the proper way to terminate a win32 console process and executes its cleanup code?
This is one way to do it, though I would suggest you use an event HANDLE and WaitForSingleObject, as it would tend to be considerably more "yielding". I left the high velocity spin-loop in this just for you to peg one of your cores while still seeing the handler is intercepted.
I took the liberty of modifying your running state to be atomically evaluated and set respectively, as I didn't want the optimizer throwing out the eval in the main loop.
#include <iostream>
#include <cstdlib>
#include <windows.h>
// using an event for monitoring
LONG running = 1;
BOOL WINAPI consoleHandler(DWORD signal)
{
if (signal == CTRL_C_EVENT)
{
std::out << "Received Ctrl-C; shutting down..." << std::endl;
InterlockedExchange(&running, 0);
return TRUE;
}
return FALSE;
}
int main(int argc, char **argv)
{
if (!SetConsoleCtrlHandler(consoleHandler, TRUE))
{
std::cerr << "Error: " << GetLastError() << '\n';
return EXIT_FAILURE;
}
std::cout << "Main thread working hard...\n";
while (InterlockedCompareExchange(&running, 0, 0) == 1);
std::cout << "Graceful shutdown received. Shutting down now." << std::endl;
return 0;
}
Output (note: I pressed ctrl-C, in case it wasn't obvious)
Main thread working hard...
Received Ctrl-C; shutting down...
Graceful shutdown received. Shutting down now.
Note: I tested this in debug and release in both 64 and 32 bit processes, no issues. And you can run it from the VS debugger. Just select "Continue" when informed you can continue if you have a handler installed, which you do.
On Windows you can use a signal handler as well:
static void shutdown(int signum)
{
printf("got signal #%d, terminating\n", signum);
// cleanup
_exit(1);
}
signal(SIGINT, shutdown);
signal(SIGTERM, shutdown);
signal(SIGSEGV, shutdown);
Ctrl-C is mapped to SIGINT just like on Linux.
This won't handle the user closing the console window using mouse, however.
Related
I have two program running on my Raspberry Pi. One interfaces with a user, the other listens for messages and updates a message file when directed. I want the other to signal to the first that the messages have been updated so the first can reload the message file. I though a SIGUSR1 signal would do what I need. However, when I raise the signal, it terminates my program, which still needs to continue listening for new messages. I therefore constructed the test case program "test_raise.cpp":
#include <iostream>
#include <csignal>
int main(){
std::cout << "Ready to raise SIGUSR1." << std::endl;
std::raise(SIGUSR1);
std::cout << "SIGUSR1 has been raised." << std::endl;
}
I am using this compiler:
gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
which generates the following output
pi#raspberrypi:~$./test_raise
Ready to raise SIGUSR1.
User defined signal 1
pi#raspberrypi:~$
Note that the 2nd text output is not produced. None of the documentation I have looked at indicates that raise terminates the issuing program. (Have I missed something?)
Is this a normal function of raise? Is there a way to do signals without terminating the program? What is my better alternative?
Thanks...
Based on a response, I have a program (invoked prior to the raise program) which has a handler for the USR1 signal:
#include <iostream>
#include <csignal>
#include <unistd.h>
bool flag;
void signalHandler( int signum ) {
std::cout << "Interrupt signal (" << signum
<< ") received." << std::endl;
flag = true;
exit(signum);
}
int main () {
signal(SIGUSR1, signalHandler);
flag = false;
while(1) {
std::cout << "Sleeping...." << std::endl;
if (flag){
std::cout << "SIGUSR1 reception noted by main. "
<< std::endl;
flag = false;
}
sleep(1000*1000); // sleep 1 second
}
return 0;
}
Now there is a handler, but the messages was never received and the raise program still terminates prior to the final message. What am I missing here?
If you haven't installed a signal handler to catch and deal with SIGUSR1 then the default behaviour is to terminate the process.
If you intend to handle the signal, then install an appropriate signal handler and do what you need to do to handle the signal. (Remember that there are very few things you are allowed to do in a signal handler).
First off, allow me to describe my scenario:
I developed a supervisory program on Linux that forks and then uses execv(), in the child process, to launch my multi-threaded application. The supervisory program is acting as a watchdog to the multi-threaded application. If the multi-threaded application does not send a SIGUSR1 signal to the supervisor after a period of time then the supervisory program will kill the child using the pid_t from the fork() call and repeat the process again.
Here is the code for the Supervisory Program:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <cerrno>
time_t heartbeatTime;
void signalHandler(int sigNum)
{
//std::cout << "Signal (" << sigNum << ") received.\n";
time(&heartbeatTime);
}
int main(int argc, char *argv[])
{
pid_t cpid, ppid;
int result = 0;
bool programLaunched = false;
time_t now;
double timeDiff;
int error;
char ParentID[25];
char *myArgv[2];
// Get the Parent Process ID
ppid = ::getpid();
// Initialize the Child Process ID
cpid = 0;
// Copy the PID into the char array
sprintf(ParentID, "%i", ppid);
// Set up the array to pass to the Program
myArgv[0] = ParentID;
myArgv[1] = 0;
// Print out of the P PID
std::cout << "Parent ID: " << myArgv[0] << "\n";
// Register for the SIGUSR1 signal
signal(SIGUSR1, signalHandler);
// Register the SIGCHLD so the children processes exit fully
signal(SIGCHLD, SIG_IGN);
// Initialize the Heart Beat time
time(&heartbeatTime);
// Loop forever and ever, amen.
while (1)
{
// Check to see if the program has been launched
if (programLaunched == false)
{
std::cout << "Forking the process\n";
// Fork the process to launch the application
cpid = fork();
std::cout << "Child PID: " << cpid << "\n";
}
// Check if the fork was successful
if (cpid < 0)
{
std::cout << "Error in forking.\n";
// Error in forking
programLaunched = false;
}
else if (cpid == 0)
{
// Check if we need to launch the application
if (programLaunched == false)
{
// Send a message to the output
std::cout << "Launching Application...\n";
// Launch the Application
result = execv("./MyApp", myArgv);
std::cout << "execv result = " << result << "\n";
// Check if the program launched has failed
if (result != -1)
{
// Indicate the program has been launched
programLaunched = true;
// Exit the child process
return 0;
}
else
{
std::cout << "Child process terminated; bad execv\n";
// Flag that the program has not been launched
programLaunched = false;
// Exit the child process
return -1;
}
}
}
// In the Parent Process
else
{
// Get the current time
time(&now);
// Get the time difference between the program heartbeat time and current time
timeDiff = difftime(now, heartbeatTime);
// Check if we need to restart our application
if ((timeDiff > 60) && (programLaunched == true))
{
std::cout << "Killing the application\n";
// Kill the child process
kill(cpid, SIGINT);
// Indicate that the process was ended
programLaunched = false;
// Reset the Heart Beat time
time(&heartbeatTime);
return -1;
}
// Check to see if the child application is running
if (kill(cpid, 0) == -1)
{
// Get the Error
error = errno;
// Check if the process is running
if (error == ESRCH)
{
std::cout << "Process is not running; start it.\n";
// Process is not running.
programLaunched = false;
return -1;
}
}
else
{
// Child process is running
programLaunched = true;
}
}
// Give the process some time off.
sleep(5);
}
return 0;
}
This approach worked fairly well until I ran into a problem with the library I was using. It didn't like all of the killing and it basically ended up tying up my Ethernet port in an endless loop of never releasing - not good.
I then tried an alternative method. I modified the supervisory program to allow it to exit if it had to kill the multi-threaded application and I created a script that will launch the supervisor program from crontab. I used a shell script that I found on Stackoverflow.
#!/bin/bash
#make-run.sh
#make sure a process is always running.
export DISPLAY=:0 #needed if you are running a simple gui app.
process=YourProcessName
makerun="/usr/bin/program"
if ps ax | grep -v grep | grep $process > /dev/null
then
exit
else
$makerun &
fi
exit
I added it to crontab to run every minute. That was very helpful and it restarted the supervisory program which in turn restarted multi-threaded application but I noticed a problem of multiple instances of the multi-threaded application being launched. I'm not really sure why this was happening.
I know I'm really hacking this up but I'm backed into a corner with this implementation. I'm just trying to get it to work.
Suggestions?
This is my code:
void* task1(void* unused)
{
try {
cout << "Run Thread" << endl;
}catch (const char* msg) {
cout << msg << endl;
}
}
int main(int argc, char *argv[])
{
try {
pthread_t thread_id;
int res = pthread_create(&thread_id, NULL, &task1, NULL);
cout << res << std::endl;
exit(EXIT_SUCCESS);
}catch (const char* msg) {
cout << msg << endl;
}
}
In Ubuntu Code RUN.
In CentOS Code NOT RUN, if my use pthread_join(thread_id, NULL); code is run but can waiting pthread complete. I try pthread_tryjoin_np but code not run.
Please help me run code in centos is no wating
If the program main() exits before the thread actually starts (and runs to the point cout << ...), the thread will be terminated and not continue to run.
I.e. you need to wait with pthread_join() before the main() exits.
The case in Ubuntu is a pure coincidence, that the thread manages to print the line before it is terminated by the C++ runtime after the main() exits.
If you do not want to wait because you want to start multiple threads, you can use thread pool (array of threads). First you start all of them, and then you pthread_join() wait for all of them to finish.
Also, if the pthread_join() blocks although the thread terminated, make sure you created the thread as joinable. That is the default, so make sure that you do not explicitly set the thread attributes to PTHREAD_CREATE_DETACHED.
To be absolutely sure, you can provide thread create attributes explicitly and ensure that the thread is created as joinable:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread_id, &attr, &task1, NULL);
pthread_attr_destroy(&attr);
pthread_join(thread_id, NULL);
(error handling not included)
Why you do not use C ++ 11? Standard library (STL) have the opportunity to develop crossplatform applications with threads. You can test on cpp.sh
#include <iostream>
#include <thread>
void task1(int used)
{
std::cout << "Run Thread " << used << std::endl;
}
int main()
{
std::thread thr(task1,1);
thr.join();
return 0;
}
OR
#include <iostream>
#include <thread>
#include <chrono>
bool bThread = false;
void task1(int used)
{
std::cout << "Run Thread " << used << std::endl;
bThread = true;
}
int main()
{
std::thread thr(task1,1);
try
{
thr.detach();
while (!bThread) std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
catch(...) { return 1; }
return 0;
}
I need to disable SIGPIPE on CentOS application, because this signal crashes my application when it works with unstable Internet connection.
I use following code in main function:
signal(SIGPIPE, SIG_IGN);
However, program still crashes with SIGPIPE. What is the reason? Have I to call this function on each thread, or it is enough to call in main function, and program will ignore SIGPIPE globally? And if it is not required to be called on each thread, why SIGPIPE still crashes program if it is supposed to ignore the signal?
Here it is a code sample that let you set up your own signal handler on linux, catch SIGPIPE and do something with that.
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <system_error>
#include <iostream>
static sigset_t theMask;
static int count = 0;
static void
signalWrapper(
int theSignalNumber,
siginfo_t* theSignalDescription,
void* theUserContext)
{
// Do something here as reaction to you SIGPIPE
// This is better way to react on such things
std::cout << "Got signal " << theSignalNumber << std::endl;
// Reinstall handler
struct ::sigaction sa;
sa.sa_sigaction = &signalWrapper;
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
try
{
if (::sigaction(theSignalNumber, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
count++;
}
void
setupSignalHandlers()
{
struct ::sigaction sa;
// Prepare mask
sigemptyset(&theMask);
sigaddset(&theMask, SIGPIPE);
// Add some more if you need it to process
sa.sa_mask = theMask;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = &signalWrapper;
// Perform setup
try
{
if (::sigaction(SIGPIPE, &sa, NULL) == -1)
throw std::error_code(errno, std::system_category());
}
catch (const std::error_code& ec)
{
std::cerr << ec << std::endl;
}
}
int
main()
{
std::cout << "Set handler!" << std::endl;
setupSignalHandlers();
std::cout << "Emit 5 SIGPIPE signals" << std::endl;
while (count < 5)
{
kill(getpid(), SIGPIPE);
usleep(100);
}
return 0;
}
and output:
Set handler!
Emit 5 SIGPIPE signals
Got signal 13
Got signal 13
Got signal 13
Got signal 13
Got signal 13
I provide signal handler since it is more correct to process signal that breaks your application than ignore it. Perhaps you need to reestablish connection or do some other stuff.
According to the man page for Signal(2), "The Effects of signal() in a multithreaded process are unspecified." You might try making sure to call signal() in the main thread before creating any other threads, but it's not guaranteed to work.
In any case signal() is deprecated, so I would suggest switching to sigaction(). I use it in multithreaded applications all the time without any problems.
I'm trying to write a simulation that will carry on running until I press a certain key (like 'q' for quit). Then after I press that, I want the program to finish writing the data its currently writing, close files, then gracefully exit (as opposed to just pressing ctrl+c to force the program to stop). Is there any way to do this on C++?
Thanks
Have the user press CTRL-C, but install a signal handler to deal with it. In the signal handler, set a global boolean variable, for example user_wants_to_quit. Then your sim loop can look like:
while ( work_to_be_done && !user_wants_to_quit) {
…
}
// Loop exited, clean up my data
A complete POSIX program (sorry, if you were hoping for Microsoft Windows), including setting and restoring the SIGINT (CTRL-C) handler:
#include <iostream>
#include <signal.h>
namespace {
sig_atomic_t user_wants_to_quit = 0;
void signal_handler(int) {
user_wants_to_quit = 1;
}
}
int main () {
// Install signal handler
struct sigaction act;
struct sigaction oldact;
act.sa_handler = signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, &oldact);
// Run the sim loop
int sim_loop_counter = 3;
while( (sim_loop_counter--) && !user_wants_to_quit) {
std::cout << "Running sim step " << sim_loop_counter << std::endl;
// Sim logic goes here. I'll substitute a sleep() for the actual
// sim logic
sleep(1);
std::cout << "Step #" << sim_loop_counter << " is now complete." << std::endl;
}
// Restore old signal handler [optional]
sigaction(SIGINT, &oldact, 0);
if( user_wants_to_quit ) {
std::cout << "SIM aborted\n";
} else {
std::cout << "SIM complete\n";
}
}