In my C++ app I need to catch signal SIGSEGV, so on Linux it's easy, but on Windows I have a problem: signal from another thread didn't catch by handler.
#include <signal.h>
#include <iostream>
#include <thread>
void setPosixSignalHandler() {
signal(SIGSEGV, [&](int sig) {
std::cout << "Received SIGSEGV" << std::endl;
exit(EXIT_FAILURE);
});
}
void f() {
raise(SIGSEGV);
}
int main() {
setPosixSignalHandler();
std::thread t(f);
t.join();
return 0;
}
If I remove multithreading than it's working like a charm.
Is it possible to set a single handler for all threads?
I'm using MinGW64.
Related
I'm trying to capture thread_pool object in a lambda function. This lambda function is called inside a thread. Upon this call, it creates(obtains) a new thread with asio::post. However, it throws segmentation fault. I tried create weak ptr with shared_ptr<thread_pool> but it didn't work as well. Simple example written below,
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
void thread1(std::function<void()> createThread) {
createThread();
}
void thread2() {
cout << "You made it" << std::endl;
}
int main(int argc, char **argv) {
boost::asio::thread_pool pool(std::thread::hardware_concurrency());
std::function<void()> createThread;
createThread = [&pool] () {
boost::asio::post(pool, boost::bind(thread2));
return true;
};
boost::asio::post(pool, boost::bind(thread1, createThread));
pool.join();
}
It works if I create another thread_pool object inside the lambda function. However, this is not the right way to do this. Therefore, I am open for your suggestions.
Edit: Added libraries to code snippet and removed while loop.
I'd simplify:
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
void thread1(std::function<void()> createThread) {
createThread();
while (true) {
std::cout << "Sleeping" << std::endl;
sleep(1);
}
}
void thread2() { std::cout << "You made it" << std::endl; }
int main() {
boost::asio::thread_pool pool;
post(pool,
boost::bind(thread1, [&pool]() { post(pool, boost::bind(thread2)); }));
pool.join();
}
Note the endl that forces stdout to flush, which helps getting results you can expect.
HOWEVER
There's a code smell with:
using explicit "threads" when using a thread-pool
nullary bind expressions
createThread doesn't (create a thread)
passing references to execution contexts. Instead, pass executors
Applying these:
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
using Executor = boost::asio::thread_pool::executor_type;
void task_loop(Executor ex, std::function<void()> task) {
while (true) {
post(ex, task);
sleep(1);
}
}
void task_function() { std::cout << "Task executes" << std::endl; }
int main() {
boost::asio::thread_pool pool;
post(pool, boost::bind(task_loop, pool.get_executor(), task_function));
pool.join();
}
Prints each second:
Task executes
Task executes
...
Is this one what you look for? :
typedef std::unique_ptr<boost::asio::io_service::work> work_ptr;
std::atomic<bool> closeFlag(false);
int main(int argc, char** argv) {
boost::asio::io_service service;
// keep the workers occupied
work_ptr work(new boost::asio::io_service::work(service));
boost::thread_group workers;
for(size_t i = 0; i < std::thread::hardware_concurrency(); ++i) {
workers.create_thread([&service]() {
service.run();
});
}
service.post([] { std::cout << "You made first job"; });
service.post([] { std::cout << "You made second job"; });
while(!closeFlag) {
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
service.stop();
work.reset(); // destroy work object: signals end of work
workers.join_all(); // wait for all worker threads to finish
return 0;
}
I'm getting a crash when calling interrupt() on an outer boost::thread, which runs an inner boost::thread, which is connected to a thread_guard. It's not crashing when calling join() manually on the inner thread.
Crash:
terminate called after throwing an instance of 'boost::thread_interrupted'
Source:
https://gist.github.com/elsamuko/6e178c37fa2cf8742cb6bf512f2ff866
#include <iostream>
#include <thread>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([]{
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
});
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
LOG("Interrupting inner");
boost::thread_guard<boost::join_if_joinable> guard(inner); // crashes
// inner.join(); // works
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main(int argc, char* argv[]) {
LOG("Start");
double_interrupt();
LOG("End");
return 0;
}
Compile & Run:
http://coliru.stacked-crooked.com/a/46c512bf9a385fff
I'm running on Ubuntu 18.04. with g++ 7.5.0 and got the latest boost 1.78.0.
I opened this issue on github, too: https://github.com/boostorg/thread/issues/366
You're mixing std::thread and boost::thread.
Only Boost Thread knows about interruption points. Use that to fix:
Live On Coliru
#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while (true) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
}
});
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
std::cout << "Interrupting inner" << std::endl;
boost::thread_guard<boost::join_if_joinable> guard(inner);
}
});
std::cout << "Interrupting outer" << std::endl;
outer.interrupt();
outer.join();
}
int main() {
std::cout << "Start" << std::endl;
double_interrupt();
std::cout << "End" << std::endl;
}
Prints
Start
Interrupting outer
End
I got a solution. The problem was, that the join() of the thread_guard waits for the inner thread with a condition_variable::wait(). condition_variable::wait() itself checks, if it's interruptible and throws an exception.
The solution is to use a custom thread_guard with disable_interruption:
#include <iostream>
#include <thread>
#include <boost/thread.hpp>
#include <boost/thread/thread_guard.hpp>
#define LOG( A ) std::cout << A << std::endl;
void work() {
size_t sum = 0;
for(int i = 0; i < 1E7; ++i) { sum += 1; }
LOG("work: " << sum);
}
// helper struct to interrupt a boost::thread within a boost::thread
struct non_interruptable_interrupt_and_join_if_joinable {
template <class Thread>
void operator()(Thread& t) {
if(t.joinable()) {
boost::this_thread::disable_interruption di;
t.interrupt();
t.join();
}
}
};
void double_interrupt() {
boost::thread outer([] {
boost::thread inner([] {
while(true) {
boost::this_thread::interruption_point();
work();
}
});
{
boost::thread_guard<non_interruptable_interrupt_and_join_if_joinable> guard(inner);
LOG("Interrupting inner");
}
});
LOG("Interrupting outer");
outer.interrupt();
outer.join();
}
int main() {
LOG("Start");
double_interrupt();
LOG("End");
}
Run here:
http://coliru.stacked-crooked.com/a/a365e40a2bd574cc
I am trying to implement a graceful shutdown of a process when its output is being piped to another process. I am testing the code bellow by piping its output: ./a.out | less and pressing q when a prompt appears. Instead of expected completion of sigwait() I see invocation of signal handler instead (it is added here just to show what is going on).
#include <csignal>
#include <chrono>
#include <iostream>
#include <thread>
#include <signal.h>
int handlerSig {0};
void signalHandler(int s)
{
handlerSig = s;
std::cerr << "handlerSig: " << handlerSig << std::endl;
}
int main()
{
for (int i = 1; i < 32; ++i)
{
std::signal(i, signalHandler);
}
bool run {true};
std::thread thread {[&]
{
while (run)
{
std::cout << "ping" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds {500});
}
}};
sigset_t waitSet;
sigemptyset(&waitSet);
sigaddset(&waitSet, SIGINT);
sigaddset(&waitSet, SIGPIPE);
sigaddset(&waitSet, SIGTERM);
pthread_sigmask(SIG_BLOCK, &waitSet, nullptr);
int waitSig {0};
sigwait(&waitSet, &waitSig);
run = false;
thread.join();
std::cerr << "waitSig: " << waitSig << std::endl;
}
I get consistent results on WSL2 and CentOS machine and I would prefer to focus on solving this problem there. When running under WSL1, neither SIGINT nor SIGTERM cause completion of sigwait() unless I remove pthread_sigmask(SIG_BLOCK...), but that seems to contradict my understanding how sigwait() is supposed to be used.
You'll need to contrive some other way of noticing that the write failed, for example, ignoring SIGPIPE but setting std::cout.exceptions(ios::badbit), or handling the signal within your writing thread.
Importantly, that SIGPIPE will always be generated for your writing thread, your sigwait()ing thread notwithstanding. Certain signals arising from a thread's activity are generated exclusively for that thread, meaning they'll be delivered to or accepted by that thread only. (POSIX.1-2008 System Interfaces 2.4.1) Typically, "naturally occurring" SIGPIPEs, SIGFPEs, and SIGSEGVs work like this.
This is an example of forwarding SIGPIPE to the main thread - probably sufficient in my case:
#include <csignal>
#include <chrono>
#include <iostream>
#include <thread>
#include <signal.h>
pthread_t mainThread {pthread_self()};
void forwardSig(int sig)
{
if (not pthread_equal(pthread_self(), mainThread))
{
pthread_kill(mainThread, sig);
}
}
int main()
{
struct sigaction newAction {};
sigemptyset(&newAction.sa_mask);
newAction.sa_handler = forwardSig;
sigaction(SIGPIPE, &newAction, nullptr);
bool run {true};
std::thread thread {[&]
{
while (run)
{
std::cout << "ping" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds {500});
}
}};
sigset_t waitSet;
sigemptyset(&waitSet);
sigaddset(&waitSet, SIGINT);
sigaddset(&waitSet, SIGPIPE);
sigaddset(&waitSet, SIGTERM);
pthread_sigmask(SIG_BLOCK, &waitSet, nullptr);
int waitSig {0};
sigwait(&waitSet, &waitSig);
run = false;
thread.join();
std::cerr << "waitSig: " << waitSig << std::endl;
}
I have the following code snippet:
#include <signal.h>
#include <boost/asio.hpp>
#include <iostream>
void startAsyncWaitForSignal(boost::asio::io_service& ioService)
{
boost::asio::signal_set signals{ioService};
signals.add(SIGTERM);
signals.async_wait(
[&ioService](boost::system::error_code errorCode, int signalNumber)
{
std::cerr << errorCode.message() << std::endl;
if (!errorCode) {
std::cerr << "received signal " << signalNumber << std::endl;
startAsyncWaitForSignal(ioService);
}
}
);
}
int main() {
boost::asio::io_service ioService;
startAsyncWaitForSignal(ioService);
ioService.run();
}
I'd expect this program to wait, until the first SIGTERM is arrived, then wait to the next, then again to the next, ...
However the program is immediately terminates with the following output:
Operation canceled
What is the reason of this immediate operation cancel? I tried to make an io_service::work object, but that just changed the fact that ioService.run() was not finished, but the signal_set was still canceled immediately.
I am using boost 1.54. There is a bug fix related to asio/signals in 1.55, but that looks like a different issue.
When leaving startAsyncWaitForSignal() the local signal_set variable gets destroyed and the async_wait() call gets cancelled. The signal_set needs to live just a little longer. Move it out of startAsyncWaitForSignal() and pass it as a parameter, for example:
#include <signal.h>
#include <boost/asio.hpp>
#include <iostream>
void startAsyncWaitForSignal(boost::asio::io_service& ioService, boost::asio::signal_set& signals)
{
signals.async_wait(
[&ioService, &signals](boost::system::error_code errorCode, int signalNumber)
{
std::cerr << errorCode.message() << std::endl;
if (!errorCode) {
std::cerr << "received signal " << signalNumber << std::endl;
startAsyncWaitForSignal(ioService, signals);
}
}
);
}
int main() {
boost::asio::io_service ioService;
boost::asio::signal_set signals{ioService};
signals.add(SIGTERM);
startAsyncWaitForSignal(ioService, signals);
ioService.run();
}
I am trying to understand interrupts and am looking for a simple code that uses interrupts. Could somebody please help me with it?
Here are two examples using the alarm function. alarm causes SIGALRM to happen n seconds after you call that function.
This program will run for 3 seconds, and then die with SIGALRM.
#include <signal.h>
#include <unistd.h>
int main() {
alarm(3);
while(true);
}
In this case, we'd like to catch SIGALRM, and die gracefully with a message:
#include <signal.h>
#include <unistd.h>
#include <iostream>
volatile bool alarmed = false;
void alrm_handler(int) {
alarmed = true;
}
int main() {
signal(SIGALRM, alrm_handler);
alarm(3);
while(not alarmed);
std::cout << "done" << std::endl;
}