如何避免在C ++ 11服务器程序中为多个客户端使用多个线程

时间:2017-03-03 12:53:16

标签: c++ multithreading sockets client-server

我在接受采访时被问到这个问题,我的回答是避免使用多线程并使用“合作多任务”(单个过程)。我真的想知道我应该如何有效地处理C ++跨平台服务器中的多个客户端,而无需为每个客户端提供一个线程。 C ++ 11是否提供了一些在该上下文中有用的工具?

3 个答案:

答案 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就是其中之一。