eidheim / Simple-Web-Server

A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio. Created to be an easy way to make REST resources available from C++ applications.
MIT License
2.61k stars 751 forks source link

multithreads in http #220

Open suxunbin opened 6 years ago

suxunbin commented 6 years ago

I find a problem when I use server_http.hpp(old version) in http. qq 20180418201558 "response" is a shared_ptr type. In this way, response can send data to the client. However, qq 20180418201650 qq 20180418202443 When I let "Res" equal to "response",response can not send data to the client.

Why I can't pass a shared_ptr to another.

eidheim commented 6 years ago

What is the signature of query_thread?

suxunbin commented 6 years ago

4 6 7 8

10 12 Part of ghttp.cpp

suxunbin commented 6 years ago

shared_ptr is Ok But shared_ptr is no use when I use pointer assignment

suxunbin commented 6 years ago

1

eidheim commented 6 years ago

I could not see anything wrong after a quick look, but making a copy of the response shared_ptr should work fine. I'll have another look Tomorrow if you have not figured it out by then.

eidheim commented 6 years ago

Ah, the problem seems to be that the Res shared_ptr is kept alive too long. The response is sent when the shared_ptr is destructed, and it seems like your Res object is kept alive in a scope higher than the scope of the handler.

suxunbin commented 6 years ago

Yes,I want to store the Res object in order to use it after the handler. And I find maybe connection between server and client is not broken. But only *response this ostream doesn't send data to the client. So make a copy of the response shared_ptr would lead the ostream confusion?

suxunbin commented 6 years ago

This is the Response's define in server_http.hpp

qq 20180419113348

eidheim commented 6 years ago

In that case, you need to use Response::send to send the data you have added to the response stream to the client. See https://github.com/eidheim/Simple-Web-Server/blob/master/http_examples.cpp#L183 for an example.

suxunbin commented 6 years ago

server_http.txt

suxunbin commented 6 years ago

This is the server_http.hpp that I used. *response will send the data to the client itself,will it?

eidheim commented 6 years ago

Sadly that would be too inefficient. The data is sent when Response::send is called, or when the Response object within the shared_ptr is destroyed.

suxunbin commented 6 years ago

Actually,I'm writing a threadpool. 1 pool.create() create a daemon thread to continuously get task from tasklines and run query_thread(). Where, tasklines is a global variable 3 2 4 5 However, I find that if I don't sleep(10) in query_handler(), the daemon thread will not get response and request object. In other words, if I leave query_handler() scope, the daemon thread(detached from the server) will not get response and request object.

suxunbin commented 6 years ago

When I am in query_handler() scope,obviously the response and request object are valid wherever they are referred(for example, Task , tasklines, the daemon thread). However, when I leave query_handler() scope, the response and request object are invalid wherever they are referred. And I want the response and request object to be kept alive in a scope higher than the scope of the handler.(for example , the location of pool.create() )

suxunbin commented 6 years ago

3 Can I have a way that when I leave the scope,the response and request object are still alive? I hope that server.resource doesn't destroy the response and request object when they leave the scope.

suxunbin commented 6 years ago

I have read the https://github.com/eidheim/Simple-Web-Server/blob/master/http_examples.cpp#L183 example. 6 My purpose is to use referrence of the response and request object on the location in the picture. In other words, I hope to store referrence of the response and request object as global variables in order that other threads can use them.

eidheim commented 6 years ago

The purpose of shared_ptr's is typically to extend the lifetime of an object. When you pass the shared_ptr to query_thread, the shared_ptr is copied and thus the object's lifetime is extended. You should in general not need to store shared_ptr's globally.

suxunbin commented 6 years ago

However, I need thread scheduling. So I only store them in query_handler(). Another thread is responsible for query_thread(). I can't directly pass the shared_ptr to query_thread() in query_handler(). I need another thread to know all the shared_ptrs in order to assign.

suxunbin commented 6 years ago

For example,if there are 60 queries but I only have 30 threads in the threadpool. If I directly pass the shared_ptr to query_thread().Then there are 30 shared_ptr that can't pass.I must store them. So how should I store the rest shared_ptr so that they are still valid when they leave the scope.

eidheim commented 6 years ago

Regarding a thread pool of size 30, here is a simplified example of how I would implement this using asio:

#include "server_http.hpp"

class Workers {
public:
  boost::asio::io_service service;

private:
  boost::asio::io_service::work work;
  std::vector<std::thread> threads;

public:
  Workers(size_t number_of_threads) : work(service) {
    for(size_t c = 0; c < number_of_threads; ++c) {
      threads.emplace_back([this] {
        service.run();
      });
    }
  }
};

using namespace std;

using HttpServer = SimpleWeb::Server<SimpleWeb::HTTP>;

int main() {
  Workers workers(30);

  HttpServer server;
  server.config.port = 8080;

  server.default_resource["GET"] = [&workers](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> /*request*/) {
    workers.service.post([response] {
      this_thread::sleep_for(chrono::seconds(5)); // Simulate time-consuming work
      response->write("Work done");
    });
  };

  server.start();
}

The response-shared_ptr is here copied by capture in workers.service.post and thus kept alive throughout the handler.

suxunbin commented 6 years ago

In this way,if 30 threads are running,then what about the new shared_ptr ?

suxunbin commented 6 years ago

If use workers.service.post, how should I sort these handlers in io_service. I could not handle thest tasks according to the order of their entry.

suxunbin commented 6 years ago

11 13 I use the example you give me. But client gets nothing.

suxunbin commented 6 years ago

14 If I don't use workers.service.post(), client can directly get the data.

suxunbin commented 6 years ago

So, when I leave this scope, the response shared_ptr becomes invalid.