#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <functional>
#include <utility>
#include <unistd.h>
using namespace std;
class Track{
public:
Track(int t) : m_track(t){}
int GetTrack() { return m_track; }
void SetTrack(int track) { m_track = track; }
private:
int m_track;
};
class Observer{
public:
Observer(Track track) : m_track(track) { }
virtual void run() = 0;
virtual ~Observer(){
cout << "Observer Destructor" << endl;
}
protected:
Track m_track;
double running = 0;
};
class Rabbit : public Observer{
public:
Rabbit(Track track) : Observer(track) { }
void run(){
while(running <= m_track.GetTrack()){
running = 10;
cout << "rabbit run " << running << endl;
sleep(1);
if(running == m_track.GetTrack() / 3 * 2){
sleep(62);
}
}
cout << "Rabbit win" << endl;
//End another thread(Turtle thread);
}
~Rabbit() = default;
};
class Turtle : public Observer{
public:
Turtle(Track track) : Observer(track) { }
void run(){
while(running <= m_track.GetTrack()){
running = 10.0 / 3;
cout << "turtle run " << running << endl;
sleep(1);
}
cout << "Turtle win" << endl;
//End another thread(Rabbit thread);
}
~Turtle() = default;
};
class Judge{
public:
Judge(Track track) : m_track(track) { }
void add(Observer* observer){
observers.push_back(observer);
}
void remove(Observer* observer){
auto temp = find(observers.begin(), observers.end(), observer);
if(temp != observers.end()){
observers.erase(temp);
}
}
void notify(){
for(int i = 0; i != observers.size(); i ){
//Start the thread to execute the run function of the subclass
thread t([&](){
observers[i]->run();
});
threads.push_back(&t);
}
for(int i = 0; i != observers.size(); i ){
if(threads[i]->joinable())
threads[i]->join();
}
}
~Judge() = default;
private:
vector<Observer*> observers;
Track m_track;
vector<thread*> threads;
};
int main(){
Track track(300);
Observer* rabbit = new Rabbit(track);
Observer* turtle = new Turtle(track);
Judge* judge = new Judge(track);
judge->add(rabbit);
judge->add(turtle);
judge->notify();
delete rabbit;
delete turtle;
delete judge;
return 0;
}
I want to use the observer pattern, and call the notify function in the Judge class to notify the two subclasses to start the run function by thread, but i reported this error
terminate called without an active exception
Aborted
How to fix this problem and add features in two subclass. What this program solves is, suppose the track is 300 meters long, the speed of the tortoise is 10/3 m/s, the speed of the rabbit is 10 m/s, the tortoise keeps running, and the hare runs 2/3 of the way to the At 200 meters, after resting for 62 seconds, the tortoise won the race. try (1) Write a program to simulate the process and results of the tortoise and the hare race according to the realization principle of the observer mode
CodePudding user response:
Two issues in one place:
for(int i = 0; i != observers.size(); i ){
//Start the thread to execute the run function of the subclass
thread t([&](){
observers[i]->run();
});
threads.push_back(&t);
}
The pointer you store in the vector becomes a dangling pointer right after you pushed it to the vector, because the thread t
goes out of scope and gets destroyed. The destructor of std::thread
terminates when you didn't join
the thread.
Use a std::vector<std::thread>
and make sure the threads are alive as long as you want to use them and dont get destroyed before you join
them.
Perhaps you used pointers because std::thread
cannot be copied, but it can be moved.
CodePudding user response:
The problem is with this line:
threads.push_back(&t);
It pushes the pointer of a std::thread
object to a vector, but the std::thread
object goes out of scope directly after that. So, the std::thread
object gets destroyed and leaves a dangling pointer in the std::vector
.
Change the vector
to hold the std::thread
objects directly and use
threads.push_back(std::move(t));
to push the objects into the vector.
Also the threads
variable does not have to be a member variable. It is enough to be a local variable in the notify
function.
Full program: https://godbolt.org/z/bTWs9f69E
You can also use emplace_back
to create the thread
object in the vector
directly and use ranged based for
loops.
void notify(){
vector<thread> threads;
for(auto &observer : observers){
//Start the thread to execute the run function of the subclass
threads.emplace_back(thread([&observer](){
observer->run();
}));
}
for(auto &t : threads){
if(t.joinable())
t.join();
}
}