doc: update cpp.md (#255)
* 更新排版
更新了以下内容的排版,以适应网页的风格:
+ lambda表达式
+ 多线程
* 更新C++多线程:锁
更新以下部分:
+ `mutex`
    + 上锁——`lock`
    + 解锁——`unlock`
    + 尝试上锁——`try_lock`
+ `lock_guard<Mutex>`
    + 额外参数`std::adopt_lock`
+ `unique_lock<Mutex>`
    + 额外参数
        + `std::adopt_lock`
        + `std::try_to_lock`
        + `std::defer_lock`
    + 成员函数
        + `lock`
        + `unlock`
        + `release`
        + `owns_lock`
* 更新C++11多线程内容
更新内容:
 
+ `call_once`
+ `condition_variable` 
    + `wait`
    + `notify_one`
    + `notify_all`
+ `async`
    + `std::launch::deferred`
    + `std::launch::async`
    + `std::deferred | std::launch::async`
+ `future`
    + `wait`
    + `get`
    + `wait_for`
    + `wait_until`
+ `future_status`
    + `ready`
    + `timeout`
    + `deferred`
+ `shared_future`
			
			
This commit is contained in:
		
							
								
								
									
										326
									
								
								docs/cpp.md
									
									
									
									
									
								
							
							
						
						
									
										326
									
								
								docs/cpp.md
									
									
									
									
									
								
							@@ -602,12 +602,14 @@ auto func = []() -> return_type { };
 | 
				
			|||||||
      
 | 
					      
 | 
				
			||||||
      auto func1 = [=, &str1]() -> int
 | 
					      auto func1 = [=, &str1]() -> int
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
              return val1 == std::stoi(str1) ? val1 : val2;
 | 
					              return 	val1 == std::stoi(str1) 
 | 
				
			||||||
 | 
					                  	? val1 : val2;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
      auto func2 = [&, val1]() -> int
 | 
					      auto func2 = [&, val1]() -> int
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
              return str1 == std::to_string(val1) ? str1 : str2;
 | 
					              return 	str1 == std::to_string(val1) 
 | 
				
			||||||
 | 
					                  	? str1 : str2;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
      ```
 | 
					      ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -619,38 +621,41 @@ auto func = []() -> return_type { };
 | 
				
			|||||||
此处给出一个 Lambda 表达式的实际使用例子(当然可以使用 `str::copy`):
 | 
					此处给出一个 Lambda 表达式的实际使用例子(当然可以使用 `str::copy`):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```cpp
 | 
				
			||||||
std::vector<int> vec({1, 2, 3, 4, 5});  // vec中包含1, 2, 3, 4, 5
 | 
					// vec中包含1, 2, 3, 4, 5
 | 
				
			||||||
std::for_each(vec.begin(), vec.end(), [](int& ele) -> void
 | 
					std::vector<int> vec({1, 2, 3, 4, 5});  
 | 
				
			||||||
    {
 | 
					std::for_each(vec.begin(), vec.end(), 
 | 
				
			||||||
        std::cout << ele << " ";
 | 
					              [](int& ele) -> void
 | 
				
			||||||
    });
 | 
					    			{
 | 
				
			||||||
 | 
					        			std::cout << ele 
 | 
				
			||||||
 | 
					                        	<< " ";
 | 
				
			||||||
 | 
					    			});
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## C++多线程
 | 
					## C++多线程
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 多线程 介绍
 | 
					> g++编译选项:`-std=c++11`
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
g++编译选项:`std=c++11`,包含头文件:
 | 
					> 包含头文件:
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
- `#include <thread>`:C++多线程库
 | 
					> + `#include <thread>`:C++多线程库
 | 
				
			||||||
- `#include <mutex>`:C++互斥量库
 | 
					> + `#include <mutex>`:C++互斥量库
 | 
				
			||||||
 | 
					> + `#include <future>`:C++异步库
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 线程的创建
 | 
					### 线程的创建
 | 
				
			||||||
<!--rehype:wrap-class=row-span-2-->
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
以普通函数作为线程入口函数:
 | 
					以普通函数作为线程入口函数:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```c++
 | 
				
			||||||
void thread_entry_function_1() { }
 | 
					void entry_1() { }
 | 
				
			||||||
void thread_entry_function_2(int val) { }
 | 
					void entry_2(int val) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::thread my_thread_1(thread_entry_function_1);
 | 
					std::thread my_thread_1(entry_1);
 | 
				
			||||||
std::thread my_thread_2(thread_entry_function_2, 5);
 | 
					std::thread my_thread_2(entry_2, 5);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
以类对象作为线程入口函数:
 | 
					以类对象作为线程入口函数:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```c++
 | 
				
			||||||
class Entry
 | 
					class Entry
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    void operator()() { }
 | 
					    void operator()() { }
 | 
				
			||||||
@@ -659,23 +664,23 @@ class Entry
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Entry entry;
 | 
					Entry entry;
 | 
				
			||||||
// 调用operator()()
 | 
					// 调用operator()()
 | 
				
			||||||
std::thread my_thread_1(entry);  
 | 
					std::thread my_thread_1(entry);	
 | 
				
			||||||
// 调用Entry::entry_function
 | 
					// 调用Entry::entry_function
 | 
				
			||||||
std::thread my_thread_2(&Entry::entry_function, &entry);  
 | 
					std::thread my_thread_2(&Entry::entry_function, &entry);	
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
以lambda表达式作为线程入口函数:
 | 
					以lambda表达式作为线程入口函数:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```c++
 | 
				
			||||||
std::thread my_thread([]() -> void 
 | 
					std::thread my_thread([]() -> void 
 | 
				
			||||||
    {
 | 
					      {
 | 
				
			||||||
        // ... 
 | 
					         // ... 
 | 
				
			||||||
    });
 | 
					      });
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 线程的销毁
 | 
					### 线程的销毁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```c++
 | 
				
			||||||
thread my_thread;
 | 
					thread my_thread;
 | 
				
			||||||
// 阻塞
 | 
					// 阻塞
 | 
				
			||||||
my_thread.join();
 | 
					my_thread.join();
 | 
				
			||||||
@@ -685,13 +690,270 @@ my_thread.detach();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### `this_thread`
 | 
					### `this_thread`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```cpp
 | 
					```c++
 | 
				
			||||||
std::this_thread::get_id();    // 获取当前线程ID
 | 
					// 获取当前线程ID
 | 
				
			||||||
std::this_thread::sleep_for();  // 使当前线程休眠一段指定时间
 | 
					std::this_thread::get_id();	
 | 
				
			||||||
std::this_thread::sleep_until();// 使当前线程休眠到指定时间
 | 
					// 使当前线程休眠一段指定时间
 | 
				
			||||||
std::this_thread::yield();    // 暂停当前线程的执行,让别的线程执行
 | 
					std::this_thread::sleep_for();	
 | 
				
			||||||
 | 
					// 使当前线程休眠到指定时间
 | 
				
			||||||
 | 
					std::this_thread::sleep_until();
 | 
				
			||||||
 | 
					// 暂停当前线程的执行,让别的线程执行
 | 
				
			||||||
 | 
					std::this_thread::yield();		
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> `#include <mutex>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 锁的基本操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					创建锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::mutex m;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					上锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					m.lock();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					解锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					m.unlock();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					尝试上锁:成功返回`true`,失败返回`false`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					m.try_lock();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					解锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					m.unlock();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 更简单的锁——`std::lock_guard<Mutex>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					构造时上锁,析构时解锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::mutex m;
 | 
				
			||||||
 | 
					std::lock_guard<std::mutex> lock(m);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					额外参数:`std::adopt_lock`:只需解锁,无需上锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					// 手动上锁
 | 
				
			||||||
 | 
					m.lock();
 | 
				
			||||||
 | 
					std::lock_guard<mutex> lock(m, 
 | 
				
			||||||
 | 
					    std::adopt_lock);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `unique_lock<Mutex>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					构造上锁,析构解锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::mutex m;
 | 
				
			||||||
 | 
					std::unique_lock<mutex> lock(m);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### `std::adopt_lock`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					只需解锁,无需上锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					// 手动上锁
 | 
				
			||||||
 | 
					m.lock();
 | 
				
			||||||
 | 
					std::unique_lock<mutex> lock(m, 
 | 
				
			||||||
 | 
					    std::adopt_lock);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### `std::try_to_lock`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					尝试上锁,可以通过`std::unique_lock<Mutex>::owns_lock()`查看状态
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::unique_lock<mutex> lock(m, 
 | 
				
			||||||
 | 
					    std::try_to_lock);
 | 
				
			||||||
 | 
					if (lock.owns_lock())
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 拿到了锁
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 没有
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### `std::defer_lock`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					绑定锁,但不上锁
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::unique_lock<mutex> lock(m,
 | 
				
			||||||
 | 
					    std::defer_lock);
 | 
				
			||||||
 | 
					lock.lock();
 | 
				
			||||||
 | 
					lock.unlock();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### `std::unique_lock<Mutex>::release`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					返回所管理的`mutex`对象指针,**释放所有权。**一旦释放了所有权,那么如果原来互斥量处于互斥状态,程序员有责任手动解锁。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `std::call_once`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					当多个线程通过这个函数调用一个可调用对象时,只会有一个线程成功调用。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::once_flag flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void foo() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::call_once(flag, foo);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### `std::condition_variable`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 创建条件变量
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::condition_variable cond;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 等待条件变量被通知
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::unique_lock<std::mutex>
 | 
				
			||||||
 | 
					    lock;
 | 
				
			||||||
 | 
					extern bool predicate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 调用方式 1
 | 
				
			||||||
 | 
					cond.wait(lock);
 | 
				
			||||||
 | 
					// 调用方式 2
 | 
				
			||||||
 | 
					cond.wait(lock, predicate);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. `wait`不断地尝试重新获取并加锁该互斥量,如果获取不到,它就卡在这里并反复尝试重新获取,如果获取到了,执行流程就继续往下走
 | 
				
			||||||
 | 
					2. `wait`在获取到互斥量并加锁了互斥量之后:
 | 
				
			||||||
 | 
					    1. 如果`wait`被提供了可调用对象,那么就执行这个可调用对象:
 | 
				
			||||||
 | 
					        + 如果返回值为`false`,那么`wait`继续加锁,直到再次被notified
 | 
				
			||||||
 | 
					        + 如果返回值为`true`,那么`wait`返回,继续执行流程
 | 
				
			||||||
 | 
					    2. 如果`wait`没有第二个参数,那么直接返回,继续执行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `std::condition_variable::notify_one`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`notify_one`唤醒一个调用`wait`的线程。注意在唤醒之前要解锁,否则调用`wait`的线程也会因为无法加锁而阻塞。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `std::condition_variable::notify_all`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					唤醒所有调用`wait`的线程。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 获取线程的运行结果
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> `#include <future>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 创建异步任务
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					double func(int val); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 使用std::async创建异步任务
 | 
				
			||||||
 | 
					// 使用std::future获取结果
 | 
				
			||||||
 | 
					// future模板中存放返回值类型
 | 
				
			||||||
 | 
					std::future<double> result = 
 | 
				
			||||||
 | 
					    std::async(func, 5);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 获取异步任务的返回值
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					等待异步任务结束,但是不获取返回值:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					result.wait();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					获取异步任务的返回值:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					int val = result.get();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					注:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					+ `get()`返回右值,因此只可调用一次
 | 
				
			||||||
 | 
					+ 只要调用上述任意函数,线程就会一直阻塞到返回值可用(入口函数运行结束)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### `std::async`的额外参数
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					额外参数可以被放在`std::async`的第一个参数位置,用于设定`std::async`的行为:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. `std::launch::deferred`:入口函数的运行会被推迟到`std::future<T>::get()`或者`std::future<T>::wait()`被调用时。此时调用线程会直接运行线程入口函数,换言之,**不会创建子线程**
 | 
				
			||||||
 | 
					2. `std::launch::async`:立即创建子线程,并运行线程入口函数
 | 
				
			||||||
 | 
					3. `std::launch::deferred | std::launch::async`:默认值,由系统自行决定
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 返回值的状态
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					让当前线程等待一段时间(等待到指定时间点),以期待返回值准备好:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					extern double foo(int val) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::future<double> result = 
 | 
				
			||||||
 | 
					    async(foo, 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//返回值类型
 | 
				
			||||||
 | 
					std::future_status status;
 | 
				
			||||||
 | 
					// 等待一段时间
 | 
				
			||||||
 | 
					status = result.wait_for(
 | 
				
			||||||
 | 
						std::chrono::seconds(1)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					// 等待到某一时间点
 | 
				
			||||||
 | 
					status = result.wait_for(
 | 
				
			||||||
 | 
						std::chrono::now() +
 | 
				
			||||||
 | 
					    std::chrono::seconds(1)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在指定的时间过去后,可以获取等待的结果:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					// 返回值已经准备好
 | 
				
			||||||
 | 
					if (status == 
 | 
				
			||||||
 | 
					   	std::future_status::ready)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// 超时:尚未准备好
 | 
				
			||||||
 | 
					else if (status ==
 | 
				
			||||||
 | 
					    std::future_status::timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// 尚未启动: std::launch::deferred
 | 
				
			||||||
 | 
					else if (status ==
 | 
				
			||||||
 | 
					    std::future_status::deferred)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 多个返回值
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c++
 | 
				
			||||||
 | 
					std::shared_future<T> result;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果要多次获取结果,可以使用`std::shared_future`,其会返回结果的一个**拷贝**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					对于不可拷贝对象,可以在`std::shared_future`中存储对象的指针,而非指针本身。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
C++ 预处理器
 | 
					C++ 预处理器
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user