我在接受采访时被问到这个问题,我的回答是避免使用多线程并使用“合作多任务”(单个过程)。我真的想知道我应该如何有效地处理C ++跨平台服务器中的多个客户端,而无需为每个客户端提供一个线程。 C ++ 11是否提供了一些在该上下文中有用的工具?
答案 0 :(得分:3)
要真正避免使用多个线程,无论是您自己还是间接通过像Boost.Asio这样的库,我都会使用poll / select / epoll(选择您的颜色)来监视服务器侦听套接字以及所有客户端套接字。默认情况下,您的进程可以在没有超时的情况下坐在那里,等待套接字事件发生
然后,这取决于您的服务器进程是否自己完成所有工作,那么您可能需要找到一种方法来将较大/长处理请求拆分为较小的块,以便为其他客户端提供机会/时间段。然后构建这些处理块的队列,检查非等待套接字,然后再次处理一个块,直到块队列再次为空。
如果做了繁重的工作,例如通过数据库,将请求发送到数据库,检查套接字,检查数据库服务器的回复等,直到请求被完全处理。
答案 1 :(得分:3)
通常,您执行此操作的方式是异步处理请求,即通过回调函数处理请求,然后将这些回调函数排队,以免它们发生冲突。
同步和异步函数调用之间的区别是什么?
同步通话:调用一个函数并让它立即执行其工作。相同的线程执行调用,并且调用阻塞直到函数完成/返回;因此:在它完成之前别无他法。这是您通常在每个正常程序中执行的操作。
异步调用:在队列上放置一个函数调用,然后,可以从相同或另一个线程调用该函数。
通常,对于客户端/服务器应用程序,您永远不会使用同步调用来处理传输的数据。一旦消化了这一点,您就会了解多线程如何在那里工作,并且一切都会变得轻松!
例如,在Boost ASIO中,您可以设置在server/client receives data时调用的函数。基本上,你所做的就是告诉Boost Library:如果我的服务器收到数据(比如std::string buffer
),我希望你调用这个函数来处理这些数据。
(请注意,同步替代方案是您调用,并等到服务器收到某些内容,并且线程完全阻塞,直到收到某些内容。这根本不方便!这就是为什么同步调用不是一个好主意)。
Boost ASIO提供了类io_service
,它基本上是ASIO异步调用的处理程序。这是一个例子:
void handle_async_receive(...) { ... }
void print() {
std::cout<<"Hello!"<<std::endl;
}
int main()
{
//some stuff
io_service.post(&print);
socket.connect(endpoint); //this is synchronous, so it connects and returns after the connection process is finished
socket.async_receive(buffer, &handle_async_receive);
io_service.post(&print);
io_service.run(); //this will block until the io_service queue is empty
}
post
时,所有打印调用都不会发生。您只需将它们放在队列中,当run()
io_service
io_service
时,它们就会被执行。
对于多线程,Boost ASIO中有一个名为strand
的解决方案。在将任何功能发布到1990-08-21
之前,您需要做的就是&#34; wrap&#34;它有一股。即使链接在多个线程上,一个链也只是对函数调用进行排队。因此,与互斥量不同,它是一种非阻塞解决方案。
答案 2 :(得分:1)
我最好的建议是不要自己动手,除非你真的想这样做(即为了你的知识或学习)。
有各种各样的图书馆应该完成这项任务,
boost.asio就是其中之一。