如何在c ++的多线程环境中实现定时器

时间:2013-02-03 03:31:20

标签: c++ multithreading

我通常将单线程进程与信号处理程序一起使用,并通过将并行任务划分为多个进程来实现并发性。

现在,我正在尝试检查多线程是否可以更快。为了实现报警/定时器,我通常会注册alarmHandler并让OS发送信号。但是在多线程环境中,我不能采用这种方法,除非有一种方法可以将信号传递给特定的线程。

因此我的问题是,如何在多线程环境中实现定时器?我可以启动一个线程,让它睡眠所需的数量,然后设置一个共享变量。我还有其他选择吗?

3 个答案:

答案 0 :(得分:2)

我假设你想在不同的时间启动线程。 您可以使用sleep_until函数。 这是一个C ++ 11函数 线程将一直睡到一定时刻 http://en.cppreference.com/w/cpp/thread/sleep_until

因此,如果您有几个任务要做,您的代码将如下所示:

int PerformTask(const std::chrono::time_point<Clock,Duration>& sleep_time, TaskParameters)
{
     sleep_until(sleep_time);
     PerformTask(TaskParameters);
}

希望有所帮助,

答案 1 :(得分:1)

使用boost :: asio

实现计时器

这是我们在项目中使用的计时器类巫婆项目处理4Gbit / s互联网流量(约3.0-4.0百万计时器)。计时器适合大多数工作。

timer.h

/*
 * Timer
 * Licensed under Apache
 *
 * Author: KaiWen <wenkai1987@gmail.com>
 * Date: Apr-16-2013
 *
 */
#ifndef TIMER_H
#define TIMER_H

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/unordered_map.hpp>

typedef boost::asio::deadline_timer* timer_ptr;

namespace bs = boost::system;

class timer;
class timer_node;

class tm_callback {
public:
    explicit tm_callback(boost::function<void(timer_node&)>& f) : m_f(f)
    {
    }

    void operator()(timer_node& node, const bs::error_code& e) {
        if (!e)
            m_f(node);
    }
private:
    boost::function<void(timer_node&)> m_f;
};

class timer_node {
    friend class timer;
public:
    timer_node() {}
    timer_node(timer_ptr p, int ms, boost::function<void(timer_node&)> f) :
        m_tptr(p), m_ms(ms), m_callback(f)
    {
    }

    void reset(unsigned int ms = 0, boost::function<void(timer_node&)> f = 0) {
        if (ms)
            m_tptr->expires_from_now(boost::posix_time::milliseconds(ms));
        else
            m_tptr->expires_from_now(boost::posix_time::milliseconds(m_ms));

        if (f)
            m_tptr->async_wait(boost::bind<void>(tm_callback(f), *this, _1));
        else
            m_tptr->async_wait(boost::bind<void>(tm_callback(m_callback), *this, _1));
    }
private:
    timer_ptr m_tptr;
    int m_ms;
    boost::function<void(timer_node&)> m_callback;
};

timer.cpp

/*
 * Timer
 *
 * Licensed under Apache
 *
 * Author: KaiWen <wenkai1987@gmail.com>
 * Date: Apr-16-2013
 *
 */
#include "timer.h"
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/ptime.hpp>

namespace ba = boost::asio;

timer::timer(int thread_num) : m_next_ios(0), m_size(0) {
    for (int i = 0; i < thread_num; i++) {
        io_service_ptr p(new ba::io_service);
        work_ptr pw(new ba::io_service::work(*p));
        m_ios_list.push_back(p);
        m_works.push_back(pw);
    }

    pthread_spin_init(&m_lock, 0);
}

timer::~timer() {
    pthread_spin_destroy(&m_lock);
}

void timer::run() {
    for (size_t i = 0; i < m_ios_list.size(); i++)
        m_threads.create_thread(boost::bind(&ba::io_service::run, &*m_ios_list[i]))->detach();
}

如果您愿意,将timer.cpp与timer.h结合使用,那么只有一个头文件。一个简单的用法:

#include <stdio.h>
#include "timer.h"

timer t(3);

void callback(timer_node& nd) {
    std::cout << "time out" << std::endl;
    t.del_timer(nd);
}

int main(void) {
    t.run();

    t.add_timer(5000, callback);    // set timeout 5 seconds

    sleep(6);

    return 0;
}

实施线程专用计时器

上面的计时器有一个锁,导致程序不是很快 。你可以实现你的owen线程特殊计时器,不使用锁定,而不是阻塞,比上面的计时器更好,但这需要一个“驱动程序”并且很难实现。这是我们实现它的一种方式:

pkt = get_pkt();
if (pkt) {
    now = pkt->sec;
    timer.execut_timer(now);
}

现在,这里没有锁定,非阻止和提升你的性能,我们使用它来处理10GBit / s的互联网流量(大约8.0-9.0百万计时器)。但这是实施依赖。希望能帮到你。

答案 2 :(得分:0)

您没有指定您使用的环境(操作系统,API等),因此您获得的任何答案都必须相当普遍。

从关于启动线程并让它休眠一段时间然后设置共享变量的示例,听起来你要做的就是让多个线程在特定时间都做一些特殊的事情,对吗? / p>

如果是这样,一个简单的方法就是在产生线程之前选择闹钟时间,这样每个线程都可以事先知道何时进行特殊操作。然后,只需将每个线程编码为“观看时钟”并在指定时间执行操作。

但是,假设您事先不知道警报何时响起。在这种情况下,我认为你需要的是一种线程间通信机制。一旦你有一个方法让一个线程将信号/消息发送到另一个线程,你就可以使用它来告诉目标线程他们何时进行报警操作。

有各种各样的API可以做到这一点,但我喜欢使用的方式(因为它是跨平台可移植的并使用标准的BSD套接字API)是在产生每个线程之前创建一个完全本地的套接字连接。在Unix / Posix下,您可以通过调用socketpair()轻松完成此操作。在Windows下没有要调用的socketpair()函数,但你可以通过常用的网络调用(socket(),bind(),listen(),accept()为一个套接字,然后套接字(你可以)自己的socketpair() )和connect()创建另一个套接字并将其连接到第一端。)

一旦你有了这对连接的套接字,你的父线程只保留第一个套接字,而新生成的线程只保留第二个套接字。 Et voila,现在你的父线程和子线程可以通过套接字相互通信。例如。如果您的父线程希望子线程执行某些操作,它可以在其套接字上发送()一个字节,子线程将在其套接字上recv()该字节,反之亦然,如果子线程想要告诉父代做东西。

这样,父线程可以产生一堆线程,然后在闹钟时间到来时在每个线程的套接字上发送一个字节。同时子线程可能正在通过非阻塞recv()调用进行工作并轮询其套接字,或者如果他们喜欢在等待警报时休眠,则可能会阻塞select()或recv()或其他任何内容。 / p>

请注意,如果您不想,则不必通过socketpair发送所有跨线程数据;通常我只是锁定一个互斥锁,将命令对象添加到FIFO队列,解锁互斥锁,然后发送一个字节。当子线程接收到该字节时,它通过锁定相同的互斥锁,从FIFO队列中弹出命令对象,解锁互斥锁,然后执行命令来响应。这样,您可以使用共享内存将任意大量数据“发送”到子线程,而无需在套接字上发送大量字节。发送的一个字节仅作为唤醒子线程的“信号”。