c++11多线程学习

一.join和detach

C++中的thread对象通常来说表达了执行的线程(thread of execution),这是一个操作系统或者平台的概念。

当thread::join()函数被调用后,调用它的线程会被block,直到线程的执行被完成。基本上,这是一种可以用来知道一个线程已结束的机制。当thread::join()返回时,操作系统的执行的线程已经完成,C++线程对象可以被销毁。

当thread::detach()函数被调用后,执行的线程从线程对象中被分离,已不再被一个线程对象所表达--这是两个独立的事情。C++线程对象可以被销毁,同时OS执行的线程可以继续。如果程序想要知道执行的线程何时结束,就需要一些其它的机制。join()函数在那个thread对象上不能再被调用,因为它已经不再和一个执行的线程相关联。

去销毁一个仍然可以“joinable”的C++线程对象会被认为是一种错误。为了销毁一个C++线程对象,要么join()函数需要被调用(并结束),要么detach()函数被调用。如果一个C++线程对象当销毁时仍然可以被join,异常会被抛出。

因此,你应该在执行流程到析构函数前总是要么join,要么detach一个线程

https://www.cnblogs.com/LuckCoder/p/10950583.html

void function_1() {
	cout << "函数function_1\n";
}
int main() {
	thread t1(function_1);
	//t1.join();

	t1.detach();
	if (t1.joinable()) {
		t1.join();
	}
	return 0;
}

二.ref move

string s = "Main";
	thread t1(Fctor(), s);
	t1.join();

	thread t2(Fctor(), ref(s));
	t2.join();
	
	thread t3(Fctor(), move(s));
	t3.join();
	thread t4 = move(t3);

	cout << this_thread::get_id() << endl;
	cout << t3.get_id() << endl;
	cout << _Thrd_hardware_concurrency() << endl; //线程最大数

三.lock  lock_guard   unique_lock

lock:

void shared_print1(string id, int value) {
        m_mutex1.lock();
        cout << "From " << id << " " << value << endl;
        m_mutex1.unlock();
    }

lock_guard:

void shared_print1(string id, int value) {
        // 顺序不一样会发生死锁
        lock_guard<mutex> locker2(m_mutex2);
        lock_guard<mutex> locker1(m_mutex1);
        
        cout << "From " << id << " " << value << endl;
    }
    void shared_print2(string id, int value) {
        lock_guard<mutex> locker1(m_mutex1);
        lock_guard<mutex> locker2(m_mutex2);
        cout << "From " << id << " " << value << endl;
    }

要么使用lock函数:
        lock(m_mutex1, m_mutex2);

unique_lock:

用法更加灵活,但占用更多cpu

void shared_print1(string id, int value) {
        unique_lock<mutex> locker(m_mutex1, defer_lock);
        //..
        locker.lock();
        cout << "From " << id << " " << value << endl;
        locker.unlock();
        //..

        locker.lock();
        //....
        locker.unlock();

        // 只能移动不能复制
        unique_lock<mutex> locker2 = move(locker);
    }

四.call_once

有些代码我们只进行一次,第一种需要不断加锁,第二种只会执行一次

      {
            unique_lock<mutex> locker(m_mutex1, defer_lock);
            if (!f.is_open()) {
                f.open("log.txt");
            }

        }
        call_once(m_flag, [&]() {f.open("log.txt"); });

五.条件变量condition_variable 

牵扯到解锁,只能用unique_lock

https://www.cnblogs.com/GuoXinxin/p/11675053.html

deque<int> q;
mutex mu;
condition_variable cond;
void function_1() {
	int count = 10;
	while (count > 0) {
		unique_lock<mutex> locker(mu);
		q.push_back(count);
		locker.unlock();
		cond.notify_one();
		//cond.notify_all(); //激活所有线程
		this_thread::sleep_for(chrono::seconds(1));
		count--;
	}
}
void function_2() {
	int data = 0;
	while (data != 1) {
		unique_lock<mutex> locker(mu);
		cond.wait(locker, []() {return !q.empty(); });
		data = q.back();
		q.pop_back();
		locker.unlock();
		cout << "t2 got a value from t1 : " << data << endl;
	}
}
int main() {
	thread t1(function_1);
	thread t2(function_2);
	t1.join();
	t2.join();

生产者消费者问题:

list<int> q;
mutex mu;
condition_variable cond;
int flag;
void function_1() {
	int count = 0;
	while (count < 10) {
		unique_lock<mutex> locker(mu);
		q.push_back(count);
		cout << "生产: " << count << endl;
		locker.unlock();
		cond.notify_one();
		count++;
	}
	flag = 1;
}
void function_2() {
	int tmp;
	while (1) {
		unique_lock<mutex> locker(mu);
		cond.wait_for(locker, chrono::seconds(1) ,[]() {return !q.empty(); });
		if (flag && q.empty()) {
			break;
		}
		tmp = q.front();
		q.pop_front();
		cout << "消费: " << tmp << endl;
		locker.unlock();
	}
}
int main() {
	thread t1(function_1);
	thread t2(function_2);
	t1.join();
	t2.join();

六.future promise async

https://blog.csdn.net/jiange_zh/article/details/51602938

int factorial(future<int>& fu) {
	int res = 1;
	int N = fu.get();
	for (int i = 1; i <= N; i++) res *= i;
	return res;
}
int main() {
	promise<int> p;
	future<int> fu = p.get_future();
	future<int> fu1 = async(launch::async, factorial, ref(fu));
	p.set_value(4);
	int x = fu1.get();
	cout << "Get from child: " << x << endl;

future:

可以处理所有在线程间数据转移的必要同步,但是future模型独享同步结果的所有权。并且通过 get() 函数,一次性的获取数据,让并发访问变的毫无意义。你的并发代码没有办法让多个线程等待同一个事件。

shared_future:

可以完成让多个线程的等待

	promise<int> p;
	future<int> fu = p.get_future();
	shared_future<int> sf = fu.share();

	future<int> fu1 = async(launch::async, factorial, sf);
	future<int> fu2 = async(launch::async, factorial, sf);
	future<int> fu3 = async(launch::async, factorial, sf);

七.创建线程的几种方式

https://blog.csdn.net/mmk27_word/article/details/108187405

八.packaged_task

九:时间约束

thread t1(factorial, 5);
	this_thread::sleep_for(chrono::milliseconds(3)); //时间段
	chrono::steady_clock::time_point tp = chrono::steady_clock::now() + chrono::milliseconds(3);
	this_thread::sleep_until(tp); // 时间点

	mutex mu;
	unique_lock<mutex> locker(mu);
	locker.try_lock_for(chrono::microseconds(3));
	locker.try_lock_until(tp);

	condition_variable cond;
	cond.wait_for(locker, chrono::microseconds(3));
	cond.wait_until(locker, tp);

	promise<int> p;
	future<int> f = p.get_future();
	f.wait_for(chrono::microseconds(3));
	f.wait_until(tp);

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/108190315