在程序中实现线程的问题

时间:2011-03-22 21:57:50

标签: c++

我有以下程序:

#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 back inside" << endl;

    workerThread.join();

    delete door;
    delete remote;

    return 0;
}

我想要打印程序:

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 

但是我的实现它会像这样打印,我不知道如何使它打印良好:

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

3 个答案:

答案 0 :(得分:4)

没有任何内容表明您的启动线程必须立即执行;在join()调用显式丢弃CPU之前,可能无法运行它。虽然您可以尝试调用Boost的道德等同于yield(),但在完整的程序中,没有什么能保证您想要运行的线程 运行。

为确保您等待子线程执行,您需要使用一些thread synchronization工具,例如互斥锁或条件变量,以便您的子线程可以发出主线程信号完成任务。如果将调用移动到join()靠近生成程序的位置,则可以确定线程已完成,但这可能仅适用于玩具应用程序。在非平凡的应用程序中,您需要使用mutexcondition variable来表示线程之间特定的“完成工作”条件。

答案 1 :(得分:3)

你需要让主线程一直等到门打开:

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;

};

现在你需要修改main来确保狗叫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;
}

答案 2 :(得分:3)

首先,值得注意的是,从大多数观点来看,这几乎是线程/线程最糟糕的使用方式。特别是,这两个线程实际上都不能自己做很多事情 - 一个线程中的所有内容都需要与另一个线程中的某些东西同步。

这就是你遇到的问题 - 你没有在你需要的任何地方同步。您的序列需要看起来像这样:

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

基本上,一个线程中的每个操作都依赖于另一个线程中的某些操作,因此即使您有两个线程,也不能并行执行。

相关问题