#include <iostream>
#include <thread>
#include <memory>
#include <functional>
#include <mutex>
#include <list>
#include <future>
#include <atomic>
#include <chrono>
// 线程创建
namespace Thread {
class A {
public:
A(int a) : ma(a) {
std::cout << "A::A():" << std::this_thread::get_id() << std::endl;
}
A(const A& a) : ma(a.ma) {
std::cout << "A(const A&): " << std::this_thread::get_id() << std::endl;
}
//~A() { std::cout << "~A::A()" << std::endl; }
void operator()() {
std::cout << "A::()" << std::endl;
}
void func(int) {}
int ma = 10;
};
void func()
{
std::cout << " start running...." << std::endl;
// ....
std::cout << " end running...." << std::endl;
}
void func1(const A& a, char* ptr, std::unique_ptr<int> uq)
{
// 修改对象a不会影响主线程的0
// a虽然是引用,但实际传的的拷贝;
// 指针在detach子线程时,绝对有问题
//std::cout << "func1 -> i = " << a.ma << std::endl;
//std::cout << "func1 -> ptr = " << ptr << std::endl;
std::cout << " sub thread id : " << std::this_thread::get_id() << std::endl; // 线程ID
}
void func2(const std::unique_ptr<int>& uq)
{
std::cout << *uq.get() << std::endl;
}
void test() {
// std::cout << "main thread id : " << std::this_thread::get_id() << std::endl;
// 1、普通函数创建线程
// std::thread m_thread(func);
// A a(1);
// char ptr[] = "hello world";
// int i = 11;
// std::thread m_thread(func1, a, ptr);
// std::thread m_thread(func1, i, ptr); // detach: 传i不安全,函数的参数a在子线程构建
// std::thread m_thread(func1, A(i), ptr); // detach: 传临时对象,安全, A(i) 和 函数的参数a在主线程构建
// std::thread m_thread(func1, std::ref(a), ptr); // std::ref传递引用,对象a不会调用拷贝构造
// 传递智能指针
// std::unique_ptr<int> uq1(new int(1));
// std::unique_ptr<int> uq2 = std::make_unique<int>(1);
// std::unique_ptr<int> uq3 = std::move(uq1); // uq1为空
// std::thread m_thread(func2, std::move(uq1));
// 类的成员函数
// A a(1);
// std::thread m_thread(&A::func, a, 1); // 类A调用拷贝构造函数
// std::thread m_thread(&A::func, &a, 1); // 类A没有调用拷贝构造函数, &a 等价于 std::ref(a)
// 2、类对象创建线程
// A a;
// std::thread m_thread(a); // 对象a会被拷贝
// 3、用lambda函数创建线程
// auto lambda_func = []() {
// std::cout << "lambda func" << std::endl;
// };
// std::thread m_thread(lambda_func);
// std::thread m_thread([]() {std::cout << "lambda func" << std::endl; });
// m_thread.join(); // 主线程等待子线程执行完毕,才能继续往下执行
// m_thread.detach(); // 分离,主线程不等待子线程执行完毕,继续往下执行
// join 和 detach 不能同时使用,否则会异常
// 判断是否可以成功使用join/detach,true:可以, false:不可以
//if(m_thread.joinable()) {
// std::cout << "joinable == true" << std::endl;
//} else {
// std::cout << "joinable == false" << std::endl;
//}
// std::cout << "end...." << std::endl;
}
}
// 互斥量
namespace Mutex {
class A {
public:
void mvRead() {
for (int i = 0; i < 10000; ++i) {
std::cout << "read miValue = " << miValue << std::endl;
}
}
void mvWrite() {
for (int i = 0; i < 100; ++i) {
++miValue;
std::cout << "write miValue = " << miValue << std::endl;
}
}
private:
int miValue = 0;
};
void test() {
int a = 10;
// mutext : 互斥量
{
std::mutex m_mutex;
m_mutex.lock();
a = 10;
m_mutex.unlock();
}
// std::lock_guard
{
std::mutex m_mutex;
//std::lock_guard<std::mutex> m_lock_guard1(m_mutex); // 相当于lock....unlock
//a = 11;
// std::lock_guard的参数std::adopt_lock表示:互斥量已经被lock,不需要再lock
m_mutex.lock();
std::lock_guard<std::mutex> m_lock_guard2(m_mutex, std::adopt_lock);
a = 11;
}
// std::lock:一次锁多个互斥量
{
std::mutex m_mutex1;
std::mutex m_mutex2;
std::lock(m_mutex1, m_mutex2);
a = 11;
m_mutex1.unlock();
m_mutex2.unlock();
}
// std::unique_lock:可以自己设置lock和unclok
{
std::mutex m_mutex;
m_mutex.lock();
// std::unique_lock<std::mutex> uq_lock1(m_mutex); // 构造 并且 clok (如果mutex之前已经被lock,则会出现异常)
// std::unique_lock<std::mutex> uq_lock2(m_mutex, std::adopt_lock); // 构造 互斥量已经被lock,不需要再lock,否则lock
// std::unique_lock<std::mutex> uq_lock2(m_mutex, std::defer_lock); // 构造 但 不lock
// std::unique_lock<std::mutex> uq_lock3(m_mutex, std::try_to_lock); // 构造 尝试lock
a = 11;
// uq_lock1.unlock();
// uq_lock1.lock();
m_mutex.unlock();
}
}
}
// 条件变量
namespace Condition {
class A {
public:
// 接收
void mInMsg() {
for (int i = 0; i < 100000; ++i) {
std::cout << "插入一个元素: " << i << std::endl;
std::unique_lock<std::mutex> uq_lock(mMutex);
mlstMsg.push_back(i);
// notify_one: 唤醒wait,只能通知一个线程
mConditionVariable.notify_one();
// notify_all
}
}
// 发送
void mOutMsg() {
while(1) {
std::unique_lock<std::mutex> uq_lock(mMutex);
// wait:等待:
// 如果第二个参数的返回值时false,那么wait将解锁互斥量,并堵塞到本行堵塞到其他某个线程调用noitfy_one为止
// 如果第二个参数的返回值时true,那么wait直接返回
// 如果wait没有第二个参数,那么就跟返回false一样
// wait被唤醒后:wait不断的尝试重新获取互斥量锁,如果获取不到锁,那么流程就卡在wait这里等着获取; 如果获取到了锁(等于上锁),那么wait
mConditionVariable.wait(uq_lock, [this, &uq_lock]() {
return !mlstMsg.empty();
});
// 流程走到这,互斥锁一定锁着
std::cout << "取出一个元素: " << mlstMsg.front() << std::endl;
mlstMsg.pop_front();
uq_lock.unlock();
}
}
private:
std::list<int> mlstMsg;
std::mutex mMutex;
std::condition_variable mConditionVariable; // 条件变量
};
void test() {
A a;
std::thread in_thread(&A::mInMsg, &a);
std::thread out_thread1(&A::mOutMsg, &a);
std::thread out_thread2(&A::mOutMsg, &a);
in_thread.join();
out_thread1.join();
out_thread2.join();
}
}
// 线程返回值
namespace ThreadRetValue {
int myThread(int) {
std::cout << "sub start thread id : " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(1000); // 1s
std::this_thread::sleep_for(dura);
std::cout << "sub end thread id : " << std::this_thread::get_id() << std::endl;
return 5;
}
// std::promise
void myThread1(std::promise<int>& mPromise, int iValue) {
//std::cout << "sub start thread id : " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(1000); // 1s
std::this_thread::sleep_for(dura);
mPromise.set_value(iValue + 100); // 把结果存到promise
//std::cout << "sub end thread id : " << std::this_thread::get_id() << std::endl;
}
void myThread2(std::promise<int>& mPromise) {
std::cout << "sub start thread id : " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(1000); // 1s
std::this_thread::sleep_for(dura);
std::future<int> m_future = mPromise.get_future();
std::cout << "get value : " << m_future.get() << std::endl;
std::cout << "sub end thread id : " << std::this_thread::get_id() << std::endl;
}
class A {
public:
int myThread(int) {
std::cout << "sub start thread id : " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds dura(1000); // 1s
std::this_thread::sleep_for(dura);
std::cout << "sub end thread id : " << std::this_thread::get_id() << std::endl;
return 5;
}
};
void test() {
std::cout << "start main thread id : " << std::this_thread::get_id() << std::endl;
// std::future
// std::async
// std::shared_future
{
// std::async:创建一个线程
// std::launch::deferred:表示线程入口函数调用被延迟到wait或者get函数调用时才执行
// 如果wait或者get没有被调用,则线程入口函数不会被调用
// std::launch::deferred:延迟调用,并且没有创建新线程,是在主线程中调用的线程入口函数
// std::launch::async:在调用async函数的时候就开始创建线程
// 普通函数
// std::future<int> future = std::async(myThread, 1); // 创建一个线程并开始执行
// 类成员函数
A a;
// std::future<int> future = std::async(&A::myThread, &a, 12);
// std::future<int> future = std::async(std::launch::deferred, &A::myThread, &a, 12);
std::future<int> future = std::async(std::launch::async, &A::myThread, &a, 12);
std::cout << "continue....." << std::endl;
// 等待1s
std::future_status status = future.wait_for(std::chrono::seconds(1));
// 等待超时
if (status == std::future_status::timeout) {}
// 成功返回
else if (status == std::future_status::ready) {}
// 延迟返回
else if (status == std::future_status::deferred) {}
// 等待线程返回,本身并不返回结果
// ret.wait();
// get: 阻塞在这,等待子线程执行完毕,拿到结果,只能get一次,主要是get函数的设计是个移动语义
// std::cout << "return value : " << future.get() << std::endl;
// std::cout << "return value : " << ret.get() << std::endl; ///程序运行异常
// future.valid(); // future是否有效
// std::shared_future: get():复制数据
std::shared_future<int> sh_future1(std::move(future)); // future就空了
// std::shared_future<int> sh_future2(future.share());
std::cout << "return value : " << sh_future1.get() << std::endl;
std::cout << "return value : " << sh_future1.get() << std::endl;
}
// std::package_task:打包任务。把各种可调用对象包装起来,方便将来作为线程入口参数
{
std::packaged_task<int(int)> m_package_task(myThread);
m_package_task(1);
// std::thread m_thread(std::ref(m_package_task), 1);
// m_thread.join();
std::future<int> m_future = m_package_task.get_future();
std::cout << "return value : " << m_future.get() << std::endl;
}
// std::promise:在某个线程给它赋值,然后在其他线程把值取出来
{
std::promise<int> m_promise;
std::thread m_thread1(myThread1, std::ref(m_promise), 10);
m_thread1.join();
//std::future<int> m_future = m_promise.get_future(); // get_future之后,m_promise就不能get_future
//std::cout << "return value : " << m_future.get() << std::endl;
std::thread m_thread2(myThread2, std::ref(m_promise));
m_thread2.join();
}
std::cout << "end main thread id : " << std::this_thread::get_id() << std::endl;
}
}
// 原子操作
namespace Atomic {
// 原子操作可以理解为不需要互斥量加锁的多线程并发编程
// 互斥量加锁一般针对一段代码,原子操作一般针对一个变量
// int gInt = 0;
// std::mutex mMutex;
std::atomic<int> gAtomic = 0; // 封装一个类型为int的对象
// 原子类型指定 bool、char、int、long、指针等类型作为模板参数(不支持浮点类型和复合类型)。
void add() {
for (int i = 0; i < 10000000; ++i) {
// mMutex.lock();
// ++gInt;
// mMutex.unlock();
++gAtomic;
}
}
void test() {
std::thread thread1(add);
std::thread thread2(add);
thread1.join();
thread2.join();
// std::cout << "gInt = " << gInt << std::endl;
std::cout << "gAtomic = " << gAtomic << std::endl;
}
}
int main()
{
// Thread::test();
Mutex::test();
// Condition::test();
// ThreadRetValue::test();
// Atomic::test();
return 0;
}