我通常将单线程进程与信号处理程序一起使用,并通过将并行任务划分为多个进程来实现并发性。
现在,我正在尝试检查多线程是否可以更快。为了实现报警/定时器,我通常会注册alarmHandler并让OS发送信号。但是在多线程环境中,我不能采用这种方法,除非有一种方法可以将信号传递给特定的线程。
因此我的问题是,如何在多线程环境中实现定时器?我可以启动一个线程,让它睡眠所需的数量,然后设置一个共享变量。我还有其他选择吗?
答案 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队列中弹出命令对象,解锁互斥锁,然后执行命令来响应。这样,您可以使用共享内存将任意大量数据“发送”到子线程,而无需在套接字上发送大量字节。发送的一个字节仅作为唤醒子线程的“信号”。