开发者

Problem implementing threads in a program

开发者 https://www.devze.com 2023-02-18 21:27 出处:网络
I have the following program: #include \"stdafx.h\" #include <boost/thread/thread_time.hpp> #include <boost/thread/thread.hpp>

I have the following program:

#include "stdafx.h"
#include <boost/thread/thread_time.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
using namespace std;

class DogDoor {
    bool open;
public:
    DogDoor()
    {
        this->open = false;
    }
    void Open()
    {
        cout << "The dog door opens" << endl << endl;
        open = true;
    }
    void close()
    {
        cout << "The dog door closes" << endl << endl;
        open = false;
    }
    bool isOpen()
    {
        return open;
    }
};

class Remote {
    DogDoor* door;
public:
    Remote(DogDoor* door)
    {
        this->door = door;
    }
    void pressButton()
    {
        cout << "Pressing the remote button" << endl;
        if(door->isOpen())
        {
            door->close();
        }
        else
        {
            door->Open();
            // close after 5 seconds
            boost::posix_time::seconds workTime(5);
            boost::this_thread::sleep(workTime);
            door->close();
        }
    }
};

void threadFunc(Remote* r)
{
    r->pressButton();
}

int _tmain(int argc, _TCHAR* argv[])
{
    DogDoor* door = new DogDoor();
    Remote* remote = new Remote(door);

    cout << "Fido barks to go outside" << endl;
    boost::thread workerThread(threadFunc, remote);

    cout << "Fido has gone outside" << endl;

    cout << "Fido is all done..." << endl;

    cout << "Fido is bac开发者_Go百科k inside" << endl;

    workerThread.join();

    delete door;
    delete remote;

    return 0;
}

I want the program to print:

Fido barks to go outside
Pressing the remote button
The dog door opens
Fido has gone outside
Fido is all done...
Fido is back inside
// and then after 5 seconds it should print this
The dog door closes 

But my implementation it will print like this and I don't know how to make it print good:

Fido barks to go outside
Fido has gone outside
Fido is all done...
Fido is back inside
Pressing the remote button
The dog door opens
// this after 5 seconds
The dog door closes


Nothing says your started thread has to execute right away; it might not be scheduled to run until the join() call explicitly drops the CPU. While you could try calling Boost's moral equivalent of yield(), in full-fledged programs nothing would guarantee that the thread you want to run actually would run.

To ensure that you wait for the child thread to execute, you'll need to use some thread synchronization tools, such as a mutex or condition variable, so that your child thread can signal the main thread that it has finished the task. If you move the call to join() closer to where you spawn the program, you can be sure the thread has finished, but this might only work for a toy application. In non-trivial applications, you'll need to use a mutex or condition variable to signal specific "job done" conditions between threads.


You need to make the main thread wait until the door is open:

class DogDoor 
{
    bool open;
public:
    // If you want to go through this door you should call
    // this method. If the door is not open you are suspended.
    // until somebody opens the door.
    void goThroughDoor()
    {
        boost::unique_lock<boost::mutex> lock(mut);
        while(!open)
        {
            // Note this is a while loop here.
            // Just because all the waiting threads are un-sespended when the
            // door is opened, it does not mean that they will get scheduled
            // to run before the door closes. So after the thread wakes up and
            // starts to run we need to re-check if the door is still open.
            //
            // If it took to long to wake up, then we have to wait again for
            // the door to be opened.
            //
            // Thus this would be a good place to bark.
            // Which may cause the remote button to be pushed.
            //
            waiter.wait(mut);
        }
    }


    DogDoor()
    {
        this->open = false;
    }
    void Open()
    {
        boost::unique_lock<boost::mutex> lock(mut);
        cout << "The dog door opens" << endl << endl;
        open = true;

        waiter.notify_all();
    }
    void close()
    {
        boost::unique_lock<boost::mutex> lock(mut);
        cout << "The dog door closes" << endl << endl;
        open = false;
    }
    bool isOpen()
    {
        boost::unique_lock<boost::mutex> lock(mut);
        return open;
    }


    private:
        boost::condition_variable waiter;
        boost::mutex              mut;

};

Now you need to modify main to make sure the dog calls goThroughDoor().

int _tmain(int argc, _TCHAR* argv[])
{
    DogDoor* door = new DogDoor();
    Remote* remote = new Remote(door);

    cout << "Fido barks to go outside" << endl;
    boost::thread workerThread(threadFunc, remote);

    // This will suspend this thread if the door is locked.
    // When the door is opened the thread will resume.    
    door->goThroughDoor();


    cout << "Fido has gone outside" << endl;

    // Should check the door is open
    // When Fido tries to come in. If it is closed he will be suspended.
    // And thus will not get back in. (Note he should have a way of barking
    // if he is blocked but that I leave to you).    
    door->goThroughDoor();
    cout << "Fido is all done..." << endl;

    cout << "Fido is back inside" << endl;

    workerThread.join();

    delete door;
    delete remote;

    return 0;
}


First, it's worth noting that from most viewpoints, this is nearly the worst possible use of threads/threading. In particular, neither thread can actually do much of anything on its own -- everything in one thread requires synchronization with something in the other thread.

That's pretty much the problem you're running into -- you haven't synchronized everywhere you need to. Your sequence needs to look something like this:

Fido barks
ask door to open
wait for confirmation that door has opened
Fido leaves
Fido returns
ask door to close
wait for confirmation that door has closed
join
exit

Essentially every action in one thread depends on something in the other thread, so even though you have two threads, none of it can execute in parallel.

0

精彩评论

暂无评论...
验证码 换一张
取 消