6

I am currently developing a program that needs to download some images from the socket server,and the downloading work will execute a long time. So, I create a new std::thread to do that.

Once it's downloaded,the std::thread will call a member function of current Class, but this Class is likely to have been released. So, I got a exception.

How to solve this problem?

void xxx::fun1()
{
   ...
}
void xxx::downloadImg()
{
 ...a long time
  if(downloadComplete)
  {
   this->fun1();
  }
}
void xxx::mainProcees()
{
  std::thread* th = new thread(mem_fn(&xxx::downloadImg),this);
  th->detach();
  //if I use th->join(),the UI will be obstructed
}
Enamul Hassan
  • 5,266
  • 23
  • 39
  • 56
tobin
  • 127
  • 2
  • 8
  • Welcome to Stack Overflow! I edited your question as far as I could guess your problem. However, add explanation of code and description so that more people with knowledge of the subject will see it. Please edit in the specific error-message you're encountering in case that's necessary to identify the specific problem. Good Luck! – Enamul Hassan Jul 25 '16 at 16:30
  • 2
    Why don't you use a `std::future`? – Superlokkus Jul 25 '16 at 16:34
  • 1
    Possible duplicate of [C++0x thread interruption](http://stackoverflow.com/questions/2790346/c0x-thread-interruption) – kfsone Jul 25 '16 at 16:35
  • 1
    Generally, using threads yourself is always a bad idea. – o11c Jul 25 '16 at 17:21

1 Answers1

6

Don't detach the thread. Instead, you can have a data member that hold a pointer to the thread, and join the thread in destructor.

class YourClass {
public:
    ~YourClass() {
        if (_thread != nullptr) {
            _thread->join();
            delete _thread;
        }
    }
    void mainProcees() {
        _thread = new thread(&YourClass::downloadImg,this);
    }
private:
    thread *_thread = nullptr;
};

UPDATE

Just as @milleniumbug pointed out, you don't need dynamic allocation for the thread object, since it is movable. So the other solution is as follows.

class YourClass {
public:
    ~YourClass() {
        if (_thread.joinable())
            _thread.join();
    }
    void mainProcess() {
        _thread = std::thread(&YourClass::downloadImg, this);
    }
private:
    std::thread _thread;
};
for_stack
  • 21,012
  • 4
  • 35
  • 48
  • Thanks,I've tried this method,but it's a special occasion,the "YourClass" is a game scene, users can pop this scene at anytime,if you do ,it will obstruct a long time when users pop this scene – tobin Jul 23 '16 at 05:47
  • In this case, you have to do some synchronization between the main thread and your download thread. For example, you can have a 'stop' flag. The download thread check the flag every 1 second, if the flag has been set, then exit downloading. In the destructor, set the 'stop' flag first , then join the thread. – for_stack Jul 23 '16 at 05:54
  • thanks for your help,It works now.If the "downloadImg" function is a interface of a static lirbrary,what should I do? – tobin Jul 23 '16 at 08:32
  • 1
    If the library is designed properly, it should have an interface to stop downloading. So instead of setting the 'stop' flag, you can call this `terminate_download` interface in your destructor. If it doesn't have such an interface, there is little you can do. It's always a bad idea to terminate a thread forcefully. – for_stack Jul 23 '16 at 09:26
  • 1
    In fact,I'm dying to know how to terminate a std thread forcefully in this problem.. ,seemingly,the standard library not provide a function like this,is't it? – tobin Jul 23 '16 at 12:30
  • Forcefully terminating a thread is (almost) always bad idea. That thread may hold resources (locks, mutexes) that will be never released if thread is terminated. – el.pescado - нет войне Jul 25 '16 at 16:38
  • @el.pescado what if a thread is infact holding a lock and you need to undo that action by killing thread and leaving the "critical" lock - how would that be possible? any idea? – serup Dec 18 '19 at 08:39