1

I normally use single thread process with signal handlers and to achieve concurrency, by dividing parallel tasks into multiple process.

Now, i am trying to check if multi-threading can be faster. To implement alarms/timers, i typically register alarmHandlers and let OS send a signal. But in multi-threading environment, i cannot take this approach, UNLESS, there is a way such that signal can be delivered to a specific thread.

Hence my question, how to implement timers in multithreading environment? I can start a thread and let it sleep for desired amount and then set a shared variable. What other options do i have?

4

3 回答 3

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);
}

希望有帮助,

于 2013-08-20T22:29:14.263 回答
1

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

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

如果是这样,一种简单的方法是在生成线程之前选择警报时间,以便每个线程可以提前知道何时执行特殊操作。然后只需将每个线程编码为“看时钟”并在指定时间执行操作即可。

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

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

一旦你有一对连接的套接字,你的父线程只保留第一个套接字,而新生成的线程只保留第二个套接字。瞧,现在您的父线程和子线程可以通过套接字相互通信。例如,如果您的父线程希望子线程做某事,它可以在其套接字上发送()一个字节,子线程将在其套接字上接收该字节,反之亦然,如果子线程想告诉父线程做一点事。

这样,父线程可以产生一堆线程,然后在警报时间到达时在每个线程的套接字上发送一个字节。与此同时,子线程可能正在工作并通过非阻塞的 recv() 调用轮询他们的套接字,或者如果他们更喜欢在等待警报时睡觉,他们可以在 select() 或 recv() 或其他内部阻塞。

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

于 2013-02-03T04:16:54.527 回答
1

使用 boost::asio 实现计时器

这是我们在项目中使用的定时器类,女巫项目处理 4Gbit/s 互联网流量(约 3.0-400 万定时器)。计时器适用于最一般的工作。

计时器.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;
};

计时器.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;
}

实现线程专用定时器

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

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

现在,这里没有锁,并且无阻塞并提高您的性能,我们用它来处理 10GBit/s 的互联网流量(大约 8.0-900 万个计时器)。但这是实现依赖。希望能帮到你。

于 2013-08-21T01:30:38.730 回答