运行 个对象同时 class

Run objects of the same class simultaneously

我从昨天开始学习 C++,我想编写一个警报系统,让用户使用 Alarm 对象设置自己的警报。 我尝试的方法本身就可以正常工作,但只允许用户 运行 一个:如果我尝试使用 start 方法启动第二个警报,程序会等待第一个警报到 "ring" 开始第二个。

如何运行同时发出两个闹钟? 感谢您花时间阅读本文。 (OSX 塞拉利昂, Xcode 8.2)

main.cpp

using namespace std;

int main(int argc, const char * argv[]) {
    Alarm test(12, 12, "foo");
    test.start();

Alarm.hpp

class Alarm {
    public:
    Alarm(int hour, int minute, std::string speech);
    void start();
    void stop();
    bool isStopped() const;
    std::string getStats() const;

    private:
    int m_hour;
    int m_minute;
    std::string m_speech;
    bool m_stopped;
};

Alarm.cpp

using namespace std;

Alarm::Alarm(int hour, int minute, string speech) {
    m_hour = hour;
    m_minute = minute;
    m_speech = speech;
    m_stopped = false;
}

void Alarm::start() {
    int currentHour, currentMinute;

    while (!Alarm::isStopped()) {
        time_t now = time(NULL);
        struct tm *current = localtime(&now);

        currentHour = current->tm_hour;
        currentMinute = current->tm_min;

        if (currentHour == m_hour && currentMinute == m_minute) {
            cout << m_speech << endl;
            m_stopped = true;
        }
        else {
           this_thread::sleep_for(chrono::milliseconds(60000));
        }
     }
}    

void Alarm::stop() {
    m_stopped = true;
}

bool Alarm::isStopped() const {
    return m_stopped;
}

我能想到的最简单的方法是使用 std::threads:

int main(int argc, const char * argv[]) {        
    Alarm test1(12, 12, "foo");
    Alarm test2(12, 12, "foo");

    std::thread t1(&Alarm::start,test1);
    std::thread t2(&Alarm::start,test2);

    while(!test1.isStopped() && !test2.isStopped()) {
         this_thread::sleep_for(chrono::milliseconds(60000));
    }

    t2.join();
    t1.join();
}

并用 std::mutex, std::atomic 或类似的 m_stopped 成员变量保护:

class Alarm {
    public:
    Alarm(int hour, int minute, std::string speech);
    Alarm(const Alarm& other);
    Alarm& operator=(const Alarm& other);
    void start();
    void stop();
    bool isStopped() const;
//    std::string getStats() const;

    private:
    int m_hour;
    int m_minute;
    std::string m_speech;
    std::atomic<bool> m_stopped;
};

Alarm::Alarm(int hour, int minute, string speech) 
: m_hour(hour),m_minute(minute),m_speech(speech),m_stopped(false) {
}

Alarm::Alarm(const Alarm& other) 
: m_hour(other.m_hour),m_minute(other.m_minute),m_speech(other.m_speech),m_stopped(other.isStopped()) {
}

Alarm& Alarm::operator=(const Alarm& other) {
    m_hour = other.m_hour;
    m_minute = other.m_minute;
    m_speech = other.m_speech;
    m_stopped.store(other.isStopped());
    return *this;
}

void Alarm::start() {
    int currentHour, currentMinute;

    while (!Alarm::isStopped()) {
        time_t now = time(NULL);
        struct tm *current = localtime(&now);

        currentHour = current->tm_hour;
        currentMinute = current->tm_min;

        if (currentHour == m_hour && currentMinute == m_minute) {
            cout << m_speech << endl;
            m_stopped.store(true);
        }
        else {
           this_thread::sleep_for(chrono::milliseconds(1000));
        }
     }
}    


void Alarm::stop() {
    m_stopped.store(true);
}

bool Alarm::isStopped() const {
    return m_stopped.load();
}

请注意我在上面的示例中所做的有关复制构造函数和赋值运算符定义的更改,以正确处理 std::atomic<bool> 成员。


我有一个可编译的版本 here,如果参数正确,它应该会成功并及时完成。

您需要多线程才能执行此操作,但对于您的情况,我建议逐个检查对象。

可以 运行 每个警报在它自己的线程中,但是对于刚开始使用 C++ 的人来说这可能有点高级 - 而且它无论如何都是过大的。

处理多个警报的标准方法是搜索所有警报以找到第一个要 "ring" 的警报,并为该警报休眠足够长的时间。当它触发时,将其从列表中删除并搜索下一个将首先响铃的。 (如果您将警报保存在 std::map<time_t, Alarm>std::map<time_t, std::string> 等分类容器中,则查找第一个警报会更容易)

记得处理多个警报需要同时触发的情况。

如果您希望用户能够在系统处于 运行ning 时与系统交互(例如添加新警报、删除警报等),您仍然需要多线程 - 但您应该只曾经有一个线程为下一个警报休眠,而不是每个警报一个线程。