1

In my c++11 project, I need to generate two threads which run infinitely. Here is an example:

static vector<int> vec;
static std::mutex mtx;
static std::condition_variable cond;
static bool done = false;
void f1()
{
    while(!done)
    {
        // do something with vec and mtx
    }
}

void f2()
{
    while(!done)
    {
        // do something with vec and mtx
    }
}

thread t1(f1);
thread t2(f2);

void finish(int s)
{
    done = true;
    // what should I do???
}

int main()
{    
    signal(SIGINT, finish);
    t1.join();
    t2.join();
    return 0;
}

Normally, I won't stop or kill this program. But in case of exception, I think I need to do something for ctrl-c, which is used to kill the program. But I don't know how to quit this program properly.

If I'm right, t1 and t2 might continue executing even if the main has returned 0. So I think I need to make them detach like this:

void finish()
{
    done = true;
    t1.detach();
    t2.detach();
}

However, when I execute the program and do ctrl-c, I get an error:

terminate called after throwing an instance of 'std::system_error'

I've found this link, so I think the problem is the same: mtx and/or cond has been destroyed while t1 or t2 hasn't finished yet.

So how could I kill the program properly? Or I don't need to deal with the signal ctrl-c and the program itself knows what to do to quit properly?

Yves
  • 11,597
  • 17
  • 83
  • 180
  • 1
    No that looks almost right. Except that `done` should probably be a [`std::atomic`](http://en.cppreference.com/w/cpp/atomic/atomic) instead of a plain `bool`. If you detach the threads they can't be joined. – Some programmer dude Aug 31 '17 at 08:56
  • 1
    And to alleviate your worries: For an undetached thread, the `join` function will not return until the thread has truly ended. That means your `main` function will not end (and the process exit) unless both threads have exited. – Some programmer dude Aug 31 '17 at 08:57
  • general rule for this kind of problems is to use thread sanitizer. Did you do that? – NoSenseEtAl Aug 31 '17 at 09:02
  • also if you use IDE like visual studio you may be able to debug it and get more info – NoSenseEtAl Aug 31 '17 at 09:03
  • @Someprogrammerdude . So I don't need to make them detach in the function `finish`? – Yves Aug 31 '17 at 09:15
  • @NoSenseEtAl . Nop, first time to hear thread sanitizer . :D – Yves Aug 31 '17 at 09:15
  • No, not if you want to join them, and wait for their exit. – Some programmer dude Aug 31 '17 at 09:19
  • @Yves but you have 1740 points, it is a requirement :P Anyway you will need either gcc or clang since VS does not support it. https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual – NoSenseEtAl Aug 31 '17 at 09:23
  • @NoSenseEtAl . wow . that's wonderful. – Yves Aug 31 '17 at 09:32
  • @Someprogrammerdude . I just tested again. I think I can't use detach because I always get the same error. I think the reason is just as the link said: the mutex is free because the main has finished while the thread hasn't finished. So I have to wait for their exit. – Yves Aug 31 '17 at 09:43
  • If you call `join` on a detached thread an exception will be thrown. For starters. And as I told you multiple times, if you call `join` before the `main` function ends you will not have a problem. – Some programmer dude Aug 31 '17 at 09:44
  • @Someprogrammerdude . It woks! Could you make an answer? I would like to accept that. – Yves Aug 31 '17 at 11:01

1 Answers1

1

done should be std::atomic<bool>, or unsequenced reads/writes are not legal.

Accessing atomic variables is only safe in a signal handler if std::atomic<bool>::is_lock_free is true. Check that. If it isn't true, your program should probably abort with an error in main.

When you .join(), you wait for the thread to finish executing. And you don't want to exit main unless the threads have finished.

In short, do this:

static std::atomic<bool> done = false;

(rest of code goes here)

int main()
{    
  if (!done.is_lock_free()) return 10; // error
  signal(SIGINT, finish);
  t1.join();
  t2.join();
}
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524