2017-01-02 63 views
2

考虑这个代码(由Simple-Web-Server提取,但图书馆的知识不应该是必要回答这个问题):这里是否需要内存隔离?

HttpServer server; 
thread server_thread; 

server.config.port = 8080; 
server.default_resource["GET"] = [](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { 
    string content = "Hello world!" 
    *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.size() << "\r\n\r\n" << content; 
}; 

server_thread = thread([&server]() { 
    server.start(); 
}); 

HttpServer::default_resource是一个std :: unordered_map,其中,以我的理解,是不是线程安全的。 port是一个未签名的短。

假设我的C++内存栅栏的理解是正确的,server,通过新的线程所看到,可能不是一个有效的状态为主线可能不会写的变化portdefault_resource从其他线程访问内存。因此,server.start()可能无法正常工作。

为了解决这个问题,我将不得不通过增加修改代码以atomic_thread_fence S:

HttpServer server; 
thread server_thread; 

server.config.port = 8080; 
server.default_resource["GET"] = [](shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request) { 
    string content = "Hello world!" 
    *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.size() << "\r\n\r\n" << content; 
}; 

atomic_thread_fence(memory_order_release); 

server_thread = thread([&server]() { 
    atomic_thread_fence(memory_order_acquire); 
    server.start(); 
}); 

我的理解是正确的,并且都是在atomic_thread_fence小号有必要吗?

+3

由线程初始化之前排序的父线程执行的所有操作必须从刚刚创建的线程的角度完成。因此,在这种情况下,由于服务器在调用'std :: thread :: thread()'之前已经初始化,所以不需要线程围栏。 –

+0

看来你正在将实际线程(并发概念)与线程处理程序对象(一个C++对象)混淆。 –

回答

5

30.3.1.2线构造

template <class F, class ...Args> 
explicit thread(F&& f, Args&&... args); 

同步:构造 的调用的完成同步与f副本的调用开始。

换句话说:当线程函数被调用时,它将与父线程中发生的所有事情同步,直到std::thread在父线程中被构造。

需要这种类型的显式记忆障碍/栅栏。

+0

OPs代码的工作原理并不仅仅是因为'server'是作为参数传递的,那时所有影响该变量的副作用代码都必须被执行?假设例如'server'没有被作为参数传递,而是全局的 - 如果我正确地理解了事情,那么会导致同步问题。引用的文字只是说线程构造函数必须在线程回调之前执行。 – Lundin

+0

即使使用pthread_create()代替std :: thread,也不需要内存栏。经验法则是:创建线程或使用互斥锁或其他同步原语等待另一个线程隐式发布所需的栅栏。你不必亲自去做。不幸的是,我无法提供证明。 –

+0

加入一个线程时是否一样,即在调用thread :: join()之后不需要显式的fences? – Bernard