mirror of
https://github.com/changkun/modern-cpp-tutorial.git
synced 2025-12-17 04:34:40 +03:00
see #2: update exercises and maintains of content
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
## 随书习题
|
## 随书习题
|
||||||
|
|
||||||
本书每章最后还加入了少量难度极小的习题,仅用于检验你是否能混合运用当前章节中的知识点。你可以在[这里](exercises)找到习题的答案,文件夹名称为章节序号。
|
本书每章最后还加入了少量难度极小的习题,仅用于检验你是否能混合运用当前章节中的知识点。你可以在[这里](./exercises)找到习题的答案,文件夹名称为章节序号。
|
||||||
|
|
||||||
## 本书网站
|
## 本书网站
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Each chapter of this book has a lot of code. If you encounter problems when writ
|
|||||||
|
|
||||||
## Exercises
|
## Exercises
|
||||||
|
|
||||||
There are few exercises At the end of each chapter of the book. It is for testing whether you can use the knowledge points in the current chapter. You can find the possible answer to the problem from [here](./exercise). The folder name is the chapter number.
|
There are few exercises At the end of each chapter of the book. It is for testing whether you can use the knowledge points in the current chapter. You can find the possible answer to the problem from [here](./exercises). The folder name is the chapter number.
|
||||||
|
|
||||||
## Website
|
## Website
|
||||||
|
|
||||||
|
|||||||
@@ -76,13 +76,14 @@
|
|||||||
+ `std::regex`
|
+ `std::regex`
|
||||||
+ `std::regex_match`
|
+ `std::regex_match`
|
||||||
+ `std::match_results`
|
+ `std::match_results`
|
||||||
- [**Chapter 07 Sandard Library: Threads and Concurrency**](./07-thread.md)
|
- [**Chapter 07 Parallelism and Concurrency**](./07-thread.md)
|
||||||
+ 7.1 `std::thread`
|
+ 7.1 `std::thread`
|
||||||
+ 7.2 `std::mutex` and `std::unique_lock`
|
+ 7.2 `std::mutex` and `std::unique_lock`
|
||||||
+ 7.3 `std::future` and `std::packaged_task`
|
+ 7.3 `std::future` and `std::packaged_task`
|
||||||
+ 7.4 `std::condition_variable`
|
+ 7.4 `std::condition_variable`
|
||||||
+ 7.5 `std::atomic` and memory order
|
+ 7.5 `std::atomic` and memory order
|
||||||
+ 7.6 Transactional memory
|
+ 7.6 Transactional memory
|
||||||
|
+ 7.7 Coroutine
|
||||||
- [**Chapter 08 Sandard Library: File System**](./08-filesystem.md)
|
- [**Chapter 08 Sandard Library: File System**](./08-filesystem.md)
|
||||||
+ 8.1 Documents and links
|
+ 8.1 Documents and links
|
||||||
+ 8.2 `std::filesystem`
|
+ 8.2 `std::filesystem`
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ bar.txt sub-match[1]: bar
|
|||||||
|
|
||||||
1. [知乎『如何评价 GCC 的 C++11 正则表达式?』中原库作者 Tim Shen 的回答](http://zhihu.com/question/23070203/answer/84248248)
|
1. [知乎『如何评价 GCC 的 C++11 正则表达式?』中原库作者 Tim Shen 的回答](http://zhihu.com/question/23070203/answer/84248248)
|
||||||
2. [正则表达式库文档](http://en.cppreference.com/w/cpp/regex)
|
2. [正则表达式库文档](http://en.cppreference.com/w/cpp/regex)
|
||||||
3. [C++ 开发 Web 服务框架](https://www.shiyanlou.com/courses/568)
|
|
||||||
|
|
||||||
## 许可
|
## 许可
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
---
|
---
|
||||||
title: 第 7 章 标准库:线程与并发
|
title: 第 7 章 并行与并发
|
||||||
type: book-zh-cn
|
type: book-zh-cn
|
||||||
order: 7
|
order: 7
|
||||||
---
|
---
|
||||||
|
|
||||||
# 第 7 章 标准库:线程与并发
|
# 第 7 章 并行与并发
|
||||||
|
|
||||||
> 内容修订中
|
> 内容修订中
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
## 7.1 std::thread
|
## 7.1 线程与并行
|
||||||
|
|
||||||
|
### std::thread
|
||||||
|
|
||||||
`std::thread` 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 `<thread>` 头文件,它提供了很多基本的线程操作,例如`get_id()`来获取所创建线程的线程 ID,例如使用 `join()` 来加入一个线程等等,例如:
|
`std::thread` 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 `<thread>` 头文件,它提供了很多基本的线程操作,例如`get_id()`来获取所创建线程的线程 ID,例如使用 `join()` 来加入一个线程等等,例如:
|
||||||
|
|
||||||
@@ -179,7 +181,21 @@ consumer.join();
|
|||||||
|
|
||||||
C++11 语言层提供了并发编程的相关支持,本节简单的介绍了 `std::thread`/`std::mutex`/`std::future` 这些并发编程中不可回避的重要工具。
|
C++11 语言层提供了并发编程的相关支持,本节简单的介绍了 `std::thread`/`std::mutex`/`std::future` 这些并发编程中不可回避的重要工具。
|
||||||
|
|
||||||
> 本节提到的内容足以让我们使用不超过 100 行代码编写一个简单的线程池库,请参考习题 TODO
|
## 习题
|
||||||
|
|
||||||
|
1. 请编写一个线程池,提供如下功能:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
ThreadPool p(4); // 指定四个工作线程
|
||||||
|
|
||||||
|
// 将任务在池中入队,并返回一个 std::future
|
||||||
|
auto f = pool.enqueue([](int life) {
|
||||||
|
return meaning;
|
||||||
|
}, 42);
|
||||||
|
|
||||||
|
// 从 future 中获得执行结果
|
||||||
|
std::cout << f.get() << std::endl;
|
||||||
|
```
|
||||||
|
|
||||||
[返回目录](./toc.md) | [上一章](./06-regex.md) | [下一章 标准库:文件系统](./08-filesystem.md)
|
[返回目录](./toc.md) | [上一章](./06-regex.md) | [下一章 标准库:文件系统](./08-filesystem.md)
|
||||||
|
|
||||||
@@ -187,8 +203,6 @@ C++11 语言层提供了并发编程的相关支持,本节简单的介绍了 `
|
|||||||
|
|
||||||
1. [C++ 并发编程\(中文版\)](https://www.gitbook.com/book/chenxiaowei/cpp_concurrency_in_action/details)
|
1. [C++ 并发编程\(中文版\)](https://www.gitbook.com/book/chenxiaowei/cpp_concurrency_in_action/details)
|
||||||
2. [线程支持库文档](http://en.cppreference.com/w/cpp/thread)
|
2. [线程支持库文档](http://en.cppreference.com/w/cpp/thread)
|
||||||
3. [100 行 C++ 代码实现线程池](https://www.shiyanlou.com/teacher/courses/565)
|
|
||||||
|
|
||||||
|
|
||||||
## 许可
|
## 许可
|
||||||
|
|
||||||
|
|||||||
@@ -39,26 +39,26 @@ void no_throw() noexcept; // 不可能抛出异常
|
|||||||
```cpp
|
```cpp
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
void may_throw() {
|
void may_throw() {
|
||||||
throw true;
|
throw true;
|
||||||
}
|
}
|
||||||
auto non_block_throw = []{
|
auto non_block_throw = []{
|
||||||
may_throw();
|
may_throw();
|
||||||
};
|
};
|
||||||
void no_throw() noexcept {
|
void no_throw() noexcept {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block_throw = []() noexcept {
|
auto block_throw = []() noexcept {
|
||||||
no_throw();
|
no_throw();
|
||||||
};
|
};
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::cout << std::boolalpha
|
std::cout << std::boolalpha
|
||||||
<< "may_throw() noexcept? " << noexcept(may_throw()) << std::endl
|
<< "may_throw() noexcept? " << noexcept(may_throw()) << std::endl
|
||||||
<< "no_throw() noexcept? " << noexcept(no_throw()) << std::endl
|
<< "no_throw() noexcept? " << noexcept(no_throw()) << std::endl
|
||||||
<< "lmay_throw() noexcept? " << noexcept(non_block_throw()) << std::endl
|
<< "lmay_throw() noexcept? " << noexcept(non_block_throw()) << std::endl
|
||||||
<< "lno_throw() noexcept? " << noexcept(block_throw()) << std::endl;
|
<< "lno_throw() noexcept? " << noexcept(block_throw()) << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -66,19 +66,19 @@ return 0;
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
try {
|
try {
|
||||||
may_throw();
|
may_throw();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cout << "捕获异常, 来自 my_throw()" << std::endl;
|
std::cout << "捕获异常, 来自 my_throw()" << std::endl;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
non_block_throw();
|
non_block_throw();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cout << "捕获异常, 来自 non_block_throw()" << std::endl;
|
std::cout << "捕获异常, 来自 non_block_throw()" << std::endl;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
block_throw();
|
block_throw();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cout << "捕获异常, 来自 block_throw()" << std::endl;
|
std::cout << "捕获异常, 来自 block_throw()" << std::endl;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -116,19 +116,19 @@ C++11 引进了自定义字面量的能力,通过重载双引号后缀运算
|
|||||||
|
|
||||||
// 字符串字面量自定义必须设置如下的参数列表
|
// 字符串字面量自定义必须设置如下的参数列表
|
||||||
std::string operator"" _wow1(const char *wow1, size_t len) {
|
std::string operator"" _wow1(const char *wow1, size_t len) {
|
||||||
return std::string(wow1)+"woooooooooow, amazing";
|
return std::string(wow1)+"woooooooooow, amazing";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator"" _wow2 (unsigned long long i) {
|
std::string operator"" _wow2 (unsigned long long i) {
|
||||||
return std::to_string(i)+"woooooooooow, amazing";
|
return std::to_string(i)+"woooooooooow, amazing";
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
auto str = "abc"_wow1;
|
auto str = "abc"_wow1;
|
||||||
auto num = 1_wow2;
|
auto num = 1_wow2;
|
||||||
std::cout << str << std::endl;
|
std::cout << str << std::endl;
|
||||||
std::cout << num << std::endl;
|
std::cout << num << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -76,13 +76,14 @@
|
|||||||
+ `std::regex`
|
+ `std::regex`
|
||||||
+ `std::regex_match`
|
+ `std::regex_match`
|
||||||
+ `std::match_results`
|
+ `std::match_results`
|
||||||
- [**第 7 章 标准库: 线程与并发**](./07-thread.md)
|
- [**第 7 章 并行与并发**](./07-thread.md)
|
||||||
+ 7.1 `std::thread`
|
+ 7.1 `std::thread`
|
||||||
+ 7.2 `std::mutex` 和 `std::unique_lock`
|
+ 7.2 `std::mutex` 和 `std::unique_lock`
|
||||||
+ 7.3 `std::future` 和 `std::packaged_task`
|
+ 7.3 `std::future` 和 `std::packaged_task`
|
||||||
+ 7.4 `std::condition_variable`
|
+ 7.4 `std::condition_variable`
|
||||||
+ 7.5 `std::atomic` 与内存顺序
|
+ 7.5 `std::atomic` 与内存顺序
|
||||||
+ 7.6 事务内存
|
+ 7.6 事务内存
|
||||||
|
+ 7.7 协程
|
||||||
- [**第 8 章 标准库: 文件系统**](./08-filesystem.md)
|
- [**第 8 章 标准库: 文件系统**](./08-filesystem.md)
|
||||||
+ 8.1 文档与链接
|
+ 8.1 文档与链接
|
||||||
+ 8.2 `std::filesystem`
|
+ 8.2 `std::filesystem`
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
//
|
||||||
|
// fold.expression.cpp
|
||||||
|
//
|
||||||
|
// exercise solution - chapter 2
|
||||||
|
// modern cpp tutorial
|
||||||
|
//
|
||||||
|
// created by changkun at changkun.de
|
||||||
|
//
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
template<typename ... T>
|
template<typename ... T>
|
||||||
auto average(T ... t) {
|
auto average(T ... t) {
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
//
|
||||||
|
// structured.binding.cpp
|
||||||
|
//
|
||||||
|
// exercise solution - chapter 2
|
||||||
|
// modern cpp tutorial
|
||||||
|
//
|
||||||
|
// created by changkun at changkun.de
|
||||||
|
//
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
//
|
||||||
|
// variadic.template.parameter.pack.cpp
|
||||||
|
//
|
||||||
|
// exercise solution - chapter 2
|
||||||
|
// modern cpp tutorial
|
||||||
|
//
|
||||||
|
// created by changkun at changkun.de
|
||||||
|
//
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Makefile
|
# Makefile
|
||||||
# web_server
|
# web_server
|
||||||
#
|
#
|
||||||
# created by changkun at labex.io
|
# created by changkun at changkun.de/modern-cpp
|
||||||
#
|
#
|
||||||
|
|
||||||
CXX = g++
|
CXX = g++
|
||||||
@@ -15,15 +15,16 @@ SOURCE_HTTPS = main.https.cpp
|
|||||||
OBJECTS_HTTP = main.http.o
|
OBJECTS_HTTP = main.http.o
|
||||||
OBJECTS_HTTPS = main.https.o
|
OBJECTS_HTTPS = main.https.o
|
||||||
|
|
||||||
LDFLAGS_COMMON = -std=c++11 -O3 -pthread -lboost_system
|
LDFLAGS_COMMON = -std=c++2a -O3 -pthread -lboost_system
|
||||||
LDFLAGS_HTTP =
|
LDFLAGS_HTTP =
|
||||||
LDFLAGS_HTTPS = -lssl -lcrypto
|
LDFLAGS_HTTPS = -lssl -lcrypto
|
||||||
|
|
||||||
LPATH_COMMON = -I/usr/include/boost
|
LPATH_COMMON = -I/usr/include/boost
|
||||||
LPATH_HTTP =
|
LPATH_HTTP =
|
||||||
LPATH_HTTPS = -I/usr/include/openssl
|
LPATH_HTTPS = -I/usr/local/opt/openssl/include
|
||||||
|
|
||||||
LLIB_COMMON = -L/usr/lib
|
LLIB_COMMON = -L/usr/lib
|
||||||
|
LLIB_HTTPS = -L/usr/local/opt/openssl/lib
|
||||||
|
|
||||||
all:
|
all:
|
||||||
make http
|
make http
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace LabexWeb;
|
using namespace Web;
|
||||||
|
|
||||||
template<typename SERVER_TYPE>
|
template<typename SERVER_TYPE>
|
||||||
void start_server(SERVER_TYPE &server) {
|
void start_server(SERVER_TYPE &server) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "server.http.hpp"
|
#include "server.http.hpp"
|
||||||
#include "handler.hpp"
|
#include "handler.hpp"
|
||||||
|
|
||||||
using namespace LabexWeb;
|
using namespace Web;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// HTTP server runs in port 12345 HTTP, enable 4 threads
|
// HTTP server runs in port 12345 HTTP, enable 4 threads
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "server.https.hpp"
|
#include "server.https.hpp"
|
||||||
#include "handler.hpp"
|
#include "handler.hpp"
|
||||||
using namespace LabexWeb;
|
using namespace Web;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// HTTPS server runs in port 12345, enable 4 threads
|
// HTTPS server runs in port 12345, enable 4 threads
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace LabexWeb {
|
namespace Web {
|
||||||
struct Request {
|
struct Request {
|
||||||
// request method, POST, GET; path; HTTP version
|
// request method, POST, GET; path; HTTP version
|
||||||
std::string method, path, http_version;
|
std::string method, path, http_version;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include "server.base.hpp"
|
#include "server.base.hpp"
|
||||||
|
|
||||||
namespace LabexWeb {
|
namespace Web {
|
||||||
typedef boost::asio::ip::tcp::socket HTTP;
|
typedef boost::asio::ip::tcp::socket HTTP;
|
||||||
template<>
|
template<>
|
||||||
class Server<HTTP> : public ServerBase<HTTP> {
|
class Server<HTTP> : public ServerBase<HTTP> {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "server.http.hpp"
|
#include "server.http.hpp"
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
namespace LabexWeb {
|
namespace Web {
|
||||||
|
|
||||||
// define HTTPS type
|
// define HTTPS type
|
||||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> HTTPS;
|
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> HTTPS;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>LabEx Web Server Test</title>
|
<title>Web Server Test</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Hello world in index.html.
|
Hello world in index.html.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>LabEx Web Server Test</title>
|
<title>Web Server Test</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Hello world in test.html.
|
Hello world in test.html.
|
||||||
|
|||||||
16
exercises/7/Makefile
Normal file
16
exercises/7/Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# Makefile
|
||||||
|
#
|
||||||
|
# exercise solution - chapter 7
|
||||||
|
# modern cpp tutorial
|
||||||
|
#
|
||||||
|
# created by changkun at changkun.de/modern-cpp
|
||||||
|
#
|
||||||
|
|
||||||
|
all: $(patsubst %.cpp, %.out, $(wildcard *.cpp))
|
||||||
|
|
||||||
|
%.out: %.cpp Makefile
|
||||||
|
clang++ $< -o $@ -std=c++2a -pedantic
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.out
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
//
|
||||||
|
// main.cpp
|
||||||
|
//
|
||||||
|
// exercise solution - chapter 7
|
||||||
|
// modern cpp tutorial
|
||||||
|
//
|
||||||
|
// created by changkun at changkun.de/modern-cpp
|
||||||
|
//
|
||||||
|
|
||||||
#include <iostream> // std::cout, std::endl
|
#include <iostream> // std::cout, std::endl
|
||||||
|
|
||||||
#include <vector> // std::vector
|
#include <vector> // std::vector
|
||||||
@@ -6,7 +15,7 @@
|
|||||||
#include <thread> // std::this_thread::sleep_for
|
#include <thread> // std::this_thread::sleep_for
|
||||||
#include <chrono> // std::chrono::seconds
|
#include <chrono> // std::chrono::seconds
|
||||||
|
|
||||||
#include "ThreadPool.hpp"
|
#include "thread_pool.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -35,6 +44,6 @@ int main()
|
|||||||
for(auto && result: results)
|
for(auto && result: results)
|
||||||
std::cout << result.get() << ' ';
|
std::cout << result.get() << ' ';
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
//
|
||||||
|
// thread_pool.hpp
|
||||||
|
//
|
||||||
|
// exercise solution - chapter 7
|
||||||
|
// modern cpp tutorial
|
||||||
|
//
|
||||||
|
// created by changkun at changkun.de/modern-cpp
|
||||||
|
//
|
||||||
|
|
||||||
#ifndef THREAD_POOL_H
|
#ifndef THREAD_POOL_H
|
||||||
#define THREAD_POOL_H
|
#define THREAD_POOL_H
|
||||||
|
|
||||||
@@ -22,9 +31,8 @@ public:
|
|||||||
|
|
||||||
// enqueue new thread task
|
// enqueue new thread task
|
||||||
template<class F, class... Args>
|
template<class F, class... Args>
|
||||||
auto enqueue(F&& f, Args&&... args)
|
decltype(auto) enqueue(F&& f, Args&&... args);
|
||||||
-> std::future<typename std::result_of<F(Args...)>::type>;
|
|
||||||
|
|
||||||
// destroy thread pool and all created threads
|
// destroy thread pool and all created threads
|
||||||
~ThreadPool();
|
~ThreadPool();
|
||||||
private:
|
private:
|
||||||
@@ -45,21 +53,15 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// constructor initialize a fixed size of worker
|
// constructor initialize a fixed size of worker
|
||||||
inline ThreadPool::ThreadPool(size_t threads): stop(false)
|
inline ThreadPool::ThreadPool(size_t threads): stop(false) {
|
||||||
{
|
|
||||||
// initialize worker
|
// initialize worker
|
||||||
for(size_t i = 0;i<threads;++i)
|
for(size_t i = 0;i<threads;++i)
|
||||||
// std::vector::emplace_back :
|
// std::vector::emplace_back :
|
||||||
// append to the end of vector container
|
// append to the end of vector container
|
||||||
// this element will be constructed at the end of container, without copy and move behavior
|
// this element will be constructed at the end of container, without copy and move behavior
|
||||||
workers.emplace_back(
|
workers.emplace_back([this] { // the lambda express capture this, i.e. the instance of thread pool
|
||||||
// the lambda express capture this, i.e. the instance of thread pool
|
|
||||||
[this]
|
|
||||||
{
|
|
||||||
// avoid fake awake
|
// avoid fake awake
|
||||||
for(;;)
|
for(;;) {
|
||||||
{
|
|
||||||
|
|
||||||
// define function task container, return type is void
|
// define function task container, return type is void
|
||||||
std::function<void()> task;
|
std::function<void()> task;
|
||||||
|
|
||||||
@@ -91,19 +93,17 @@ inline ThreadPool::ThreadPool(size_t threads): stop(false)
|
|||||||
// Enqueue a new thread
|
// Enqueue a new thread
|
||||||
// use variadic templates and tail return type
|
// use variadic templates and tail return type
|
||||||
template<class F, class... Args>
|
template<class F, class... Args>
|
||||||
auto ThreadPool::enqueue(F&& f, Args&&... args)
|
decltype(auto) ThreadPool::enqueue(F&& f, Args&&... args) {
|
||||||
-> std::future<typename std::result_of<F(Args...)>::type>
|
|
||||||
{
|
|
||||||
// deduce return type
|
// deduce return type
|
||||||
using return_type = typename std::result_of<F(Args...)>::type;
|
using return_type = typename std::result_of<F(Args...)>::type;
|
||||||
|
|
||||||
// fetch task
|
// fetch task
|
||||||
auto task = std::make_shared< std::packaged_task<return_type()> >(
|
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
||||||
);
|
);
|
||||||
|
|
||||||
std::future<return_type> res = task->get_future();
|
std::future<return_type> res = task->get_future();
|
||||||
|
|
||||||
// critical section
|
// critical section
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||||
@@ -115,7 +115,7 @@ auto ThreadPool::enqueue(F&& f, Args&&... args)
|
|||||||
// add thread to queue
|
// add thread to queue
|
||||||
tasks.emplace([task]{ (*task)(); });
|
tasks.emplace([task]{ (*task)(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify a wait thread
|
// notify a wait thread
|
||||||
condition.notify_one();
|
condition.notify_one();
|
||||||
return res;
|
return res;
|
||||||
@@ -129,10 +129,10 @@ inline ThreadPool::~ThreadPool()
|
|||||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||||
stop = true;
|
stop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wake up all threads
|
// wake up all threads
|
||||||
condition.notify_all();
|
condition.notify_all();
|
||||||
|
|
||||||
// let all processes into synchronous execution, use c++11 new for-loop: for(value:values)
|
// let all processes into synchronous execution, use c++11 new for-loop: for(value:values)
|
||||||
for(std::thread &worker: workers)
|
for(std::thread &worker: workers)
|
||||||
worker.join();
|
worker.join();
|
||||||
@@ -5385,12 +5385,12 @@ S
|
|||||||
endstream
|
endstream
|
||||||
endobj
|
endobj
|
||||||
16 0 obj
|
16 0 obj
|
||||||
<</Filter/FlateDecode/Length 611>>
|
<</Filter/FlateDecode/Length 614>>
|
||||||
stream
|
stream
|
||||||
xÚ}UËŽÛ0¼÷+ôÖJEÉ@àCÑÚÛ¹=4q²§E±ýÿCI“´Ýìf‘,>†Ã¡^B‰94<08>ÆØÇp~<1F>ááK¹EÈÃñrJ±C†8fÇùç!%ø<>Rí}ˆô¿ŒÛšP×tJ©<4A>ÓPZeïšRÂÙwÄöåÊø›ÂØÙƒ¦_ÇïŒBÎq¬BdÛ0”{Û’ ù,¡yÍ QÏ–
|
xÚ}UËŽÛ0¼÷+ôÖJEJ@àCÑÚÛ¹=ÔöfO‹bûÿ‡’e»Ùd‘->†Ã¡ì^]tA~Ñ18¦êKuó‹ûxv_¢‹ì!ftç‹‹!ø’Ð
|<7C>àÎËÏSð;„\mA[Dí?Õ}OØö4…ÀugñÎ!\ú‰}ºÈ‚þ&‰ñ ñ×ù» £¯9ƒ"Bðb놔|á#
g
-{Iˆšx±T@–˜ö§Ü|P€‚Ô Ó¸¾¿G|JÛ“Ýá%W}% EèCf7@ñ²¡CnÕ‹”†”N-NÆQLµ | ||||||