多线程的一些基础语法。
std::unique_lock
使用std::unique_lock 比std::lock_guard更加灵活:std::lock_guard 不能显式的调用 lock 和 unlock,而 std::unique_lock 可以在声明后的任意位 置调用,可以缩小锁的作用范围,提供更高的并发度。
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
int v = 1;
void critical_sectin(int change_v){
static mutex mtx;
std::this_thread::sleep_for(std::chrono::milliseconds(change_v));
std::unique_lock<std::mutex> lock(mtx);
v = change_v;
std::cout << v << std::endl;
lock.unlock();
change_v++;
lock.lock();
v = change_v;
std::cout << v << std::endl;
}
int main(){
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::thread t1(critical_sectin, 590);
std::thread t2(critical_sectin, 66);
t1.join();
t2.join();
return 0;
}
std::future 对线程的返回结果进行封装
#include <iostream>
#include <mutex>
#include <thread>
#include <future>
using namespace std;
int main(){
std::packaged_task<int(int)> task([](int a) -> int{
std::cout << "inside packaged_task " << a << std::endl;
return a;
});
std::future<int> result = task.get_future();
std::thread(std::move(task), 8).detach(); //创建thread,传入package_task的参数
result.wait();
std::cout << result.get() << std::endl;
return 0;
}
std::condition_variable
用于同步,解决死锁
#include <iostream>
#include <mutex>
#include <thread>
#include <future>
#include <condition_variable>
#include <queue>
#include <string>
using namespace std;
int main(){
std::condition_variable cv;
std::mutex mtx;
std::queue<int> produced_nums;
bool notify = false;
auto producer = [&](){
for (int i=1; ; i++){
std::this_thread::sleep_for(std::chrono::milliseconds(900));
std::unique_lock<mutex> lock(mtx);
std::cout << "producing " << i << std::endl;
produced_nums.push(i);
notify = true;
cv.notify_all();
}
};
auto consumer = [&](int csid){
while (true){
unique_lock<mutex> lock(mtx);
while (!notify){
cv.wait(lock);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << csid << " lock success" << std::endl;
if (!produced_nums.empty()){
auto result = produced_nums.front();
produced_nums.pop();
std::cout << "consumer " << csid << " : " << result << " " << produced_nums.size() << std::endl;
}
notify = false;
}
};
thread produce(producer);
vector<thread> pool;
for (int i = 0; i < 10; ++i) {
pool.push_back(thread(consumer, i));
}
produce.join();
for (int i = 0; i < 10; ++i) {
pool[i].join();
}
return 0;
}
condition_variable需要mutex和condition两个变量,在cv.wait(lock)后,需要检查条件是否满足(因为存在假唤醒)。
consumer中wait被signal之后的过程:
首先要拿到lock,然后cv.wait(lock, {return is_ready;});之后,线程开始休眠,被加入一个唤醒队列,同时释放锁。
cv.notify_all()之后,所有在wait的consumer线程被唤醒,然后开始lock,注意,如果mutex此时是被locked的,这些线程也不会再休眠了,会一直尝试加锁,直到加锁成功,进入临界区。
官方样例:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}
output:
main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing