C++ 备忘清单 & cpp cheatsheet & 速查表
多线程介绍
g++编译选项:-std=c++11。包含头文件:
#include <thread>:C++多线程库#include <mutex>:C++互斥量库#include <future>:C++异步库
线程的创建
以普通函数作为线程入口函数:
void entry_1() { }
void entry_2(int val) { }
std::thread my_thread_1(entry_1);
std::thread my_thread_2(entry_2, 5);
以类对象作为线程入口函数:
class Entry
{
void operator()() { }
void entry_function() { }
};
Entry entry;
// 调用operator()()
std::thread my_thread_1(entry);
// 调用Entry::entry_function
std::thread my_thread_2(&Entry::entry_function, &entry);
以lambda表达式作为线程入口函数:
std::thread my_thread([]() -> void
{
// ...
});
线程的销毁
thread my_thread;
// 阻塞
my_thread.join();
// 非阻塞
my_thread.detach();
this_thread
// 获取当前线程ID
std::this_thread::get_id();
// 使当前线程休眠一段指定时间
std::this_thread::sleep_for();
// 使当前线程休眠到指定时间
std::this_thread::sleep_until();
// 暂停当前线程的执行,让别的线程执行
std::this_thread::yield();
锁
#include <mutex>
锁的基本操作
创建锁
std::mutex m;
上锁
m.lock();
解锁
m.unlock();
尝试上锁:成功返回true,失败返回false
m.try_lock();
解锁
m.unlock();
更简单的锁 —— std::lock_guard<Mutex>
构造时上锁,析构时解锁
std::mutex m;
std::lock_guard<std::mutex> lock(m);
额外参数:std::adopt_lock:只需解锁,无需上锁
// 手动上锁
m.lock();
std::lock_guard<mutex> lock(m,
std::adopt_lock);
unique_lock<Mutex>
构造上锁,析构解锁
std::mutex m;
std::unique_lock<mutex> lock(m);
std::adopt_lock
只需解锁,无需上锁
// 手动上锁
m.lock();
std::unique_lock<mutex> lock(m,
std::adopt_lock);
std::try_to_lock
尝试上锁,可以通过std::unique_lock<Mutex>::owns_lock()查看状态
std::unique_lock<mutex> lock(m,
std::try_to_lock);
if (lock.owns_lock())
{
// 拿到了锁
}
else
{
// 没有
}
std::defer_lock
绑定锁,但不上锁
std::unique_lock<mutex> lock(m,
std::defer_lock);
lock.lock();
lock.unlock();
std::unique_lock<Mutex>::release
返回所管理的mutex对象指针,**释放所有权。**一旦释放了所有权,那么如果原来互斥量处于互斥状态,程序员有责任手动解锁。
std::call_once
当多个线程通过这个函数调用一个可调用对象时,只会有一个线程成功调用。
std::once_flag flag;
void foo() { }
std::call_once(flag, foo);
std::condition_variable
创建条件变量
std::condition_variable cond;
等待条件变量被通知
std::unique_lock<std::mutex>
lock;
extern bool predicate();
// 调用方式 1
cond.wait(lock);
// 调用方式 2
cond.wait(lock, predicate);
wait不断地尝试重新获取并加锁该互斥量,如果获取不到,它就卡在这里并反复尝试重新获取,如果获取到了,执行流程就继续往下走wait在获取到互斥量并加锁了互斥量之后:- 如果
wait被提供了可调用对象,那么就执行这个可调用对象:- 如果返回值为
false,那么wait继续加锁,直到再次被 notified - 如果返回值为
true,那么wait返回,继续执行流程
- 如果返回值为
- 如果
wait没有第二个参数,那么直接返回,继续执行
- 如果
std::condition_variable::notify_one
notify_one 唤醒一个调用 wait 的线程。注意在唤醒之前要解锁,否则调用 wait 的线程也会因为无法加锁而阻塞。
std::condition_variable::notify_all
唤醒所有调用 wait 的线程。
获取线程的运行结果
#include <future>
创建异步任务
double func(int val);
// 使用std::async创建异步任务
// 使用std::future获取结果
// future模板中存放返回值类型
std::future<double> result =
std::async(func, 5);
获取异步任务的返回值
等待异步任务结束,但是不获取返回值:
result.wait();
获取异步任务的返回值:
int val = result.get();
注:
get()返回右值,因此只可调用一次- 只要调用上述任意函数,线程就会一直阻塞到返回值可用(入口函数运行结束)
std::async 的额外参数
额外参数可以被放在 std::async 的第一个参数位置,用于设定 std::async 的行为:
std::launch::deferred:入口函数的运行会被推迟到std::future<T>::get()或者std::future<T>::wait()被调用时。此时调用线程会直接运行线程入口函数,换言之,不会创建子线程std::launch::async:立即创建子线程,并运行线程入口函数std::launch::deferred | std::launch::async:默认值,由系统自行决定
返回值的状态
让当前线程等待一段时间(等待到指定时间点),以期待返回值准备好:
extern double foo(int val) {}
std::future<double> result =
std::async(foo, 5);
//返回值类型
std::future_status status;
// 等待一段时间
status = result.wait_for(
std::chrono::seconds(1)
);
// 等待到某一时间点
status = result.wait_until(
std::chrono::now() +
std::chrono::seconds(1)
);
在指定的时间过去后,可以获取等待的结果:
// 返回值已经准备好
if (status ==
std::future_status::ready)
{
}
// 超时:尚未准备好
else if (status ==
std::future_status::timeout)
{ }
// 尚未启动: std::launch::deferred
else if (status ==
std::future_status::deferred)
{ }
多个返回值
如果要多次获取结果,可以使用std::shared_future,其会返回结果的一个拷贝。
std::shared_future<T> result;
对于不可拷贝对象,可以在std::shared_future中存储对象的指针,而非指针本身。
创建线程
void threadFunction() {
// 线程函数体
std::cout << "From thread" << std::endl;
}
int main() {
// 创建线程并开始执行线程函数
std::thread t(threadFunction);
// 等待线程执行完毕
t.join();
return 0;
}
传递参数给线程函数
void threadFunction(int value) {
// 线程函数体
std::cout << "Received value: " << value << std::endl;
}
int main() {
int data = 42;
std::thread t(threadFunction, data);
t.join();
return 0;
}
使用Lambda表达式创建线程
int main() {
int data = 42;
std::thread t([data]() {
// Lambda 表达式作为线程函数
std::cout << "Received value: " << data << std::endl;
});
t.join();
return 0;
}
处理线程间的同步:
#include <mutex>
std::mutex mtx;
void threadFunction() {
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Thread safe output." << std::endl;
}
int main() {
std::thread t1(threadFunction);
std::thread t2(threadFunction);
t1.join();
t2.join();
return 0;
}
使用std::async启动异步任务:
#include <future>
int taskFunction() {
// 异步任务
return 42;
}
int main() {
// 启动异步任务
std::future<int> fut = std::async(std::launch::async, taskFunction);
// 获取异步任务的结果
int result = fut.get();
std::cout << "Result: " << result << std::endl;
return 0;
}