C++11多线程,thread库; mutex类,成员函数lock(), unlock();unique

C++11多线程,thread库; mutex类,成员函数lock(), unlock();unique,第1张

C++11多线程,thread库; mutex类,成员函数lock(), unlock();unique

文章目录
    • 进程和线程
      • 1. 进程
      • 2. 线程
    • C++11多线程编程
      • 1. C++11新标准
      • 2. 创建线程
        • 1. 普通函数
        • 2. 仿函数
        • 3. 成员函数
      • 4. 多线程数据保护(数据一致性)

进程和线程 1. 进程

进程就是一个在运行的可执行程序。

  1. 一个CPU(核)只能同时运行一个进程,可以在多个进程间来回跳(把进程的信息和进度等信息保存在进程表中),看起来貌似在同时运行多个进程,这叫做伪并发。
  2. 进程是不同的可执行程序,不同的内存空间,数据不共享。但也有进程间通信的方式,这里不讲,暂时没用到。
2. 线程

线程是一个任务,一个进程中可以有多个线程。

  1. 每个进程至少有一个线程(唯一的主线程),这个线程不需要自己开启,随着main()函数自己就开启了一个主线程,随着最后return,进程的结束而结束。
  2. 线程是进程中不同的任务,同一个进程间的多个线程共享数据。因此多线程编程的时候要注意数据一致性的问题,不能同时写数据,不能读着写着。
C++11多线程编程 1. C++11新标准
  1. C++11本身增加了对多线程的支持,有了可以直接用的thread库,不需要其他第三方库了(当然,也可以用)

    头文件:#include

    #include
    void func()
    {
    	cout<<"func"< 

    CMakeLists.txt文件链接到库:

    target_link_libraries(executableName pthread)
    
  2. 线程对象的.join()成员函数函数(重要)
    阻塞,等等我,等我执行完,因为线程会随着进程的结束被强制终止,所以可以在主线程中,想要子线程执行完再往下执行的地方,加入子线程.join(),阻塞该线程,等待子线程执行完。

    mythread1.join();
    
  3. 线程对象的.detach成员函数(少用)
    脱离,解耦合,这样mythread1子线程和主线程不再关联,进程结束后,子线程后台继续运行。分离后不能再.join()阻塞了,不再相互影响了。detach()用的不多,建议少用。

    mythread1.detach();
    
  4. 线程对象.joinable()成员函数
    线程是否.join()或者.detach()过,还能.join()吗,能,返回true,不能,返回false

    if(mythread1.joinable())
    	mythread1.join();
    
2. 创建线程 1. 普通函数

传入函数名和函数参数,函数名就是函数的地址,指针。
格式:thread 线程名(函数名,函数参数)

#include
#include
void func1(int a, folat b);
int main()
{
	int a;
	float b;
	//新创建线程,线程一被创建,立马开始执行。(函数名,函数参数)
	thread my_thread1(func1, a, b);
	//...
	my_thread1.join()
	return 0;
}

实例化一个线程thread对象
新线程创建出来,立刻就开始执行了。

//实例化一个thread类的对象,参数是函数名和需要传入函数的参数,没有参数就只要函数名
std::thread mythread1(func, param, param);
2. 仿函数

仿函数就在一个类内,重载()运算符,使得一个对象用()运算符时,看起来很像个函数。(用的少),此时把对象名用来直接创建线程。
格式:thread 线程名(对象名,参数)

#include
#include
using namespace std;
class A
{
public:
	void operator()(int num)  //重载()运算符,仿函数
	{cout< 
3. 成员函数 

格式:thread 线程名(成员函数的地址,对象(本身或地址或引用),参数)

// 成员函数, 对象, 成员函数的参数
thread mythread1(&A::func, obj, param)

示例:

#include
#include
using namespace std;
class A
{
public:
	void func(int num)
	{cout< 
4. 多线程数据保护(数据一致性) 

要保证读的时候不能写,写的时候不能读,多个线程不能同时 *** 作数据

  1. 互斥量std::mutex
    mutex也是一个类,也有头文件mutex,有.lock()成员函数和.unlock()成员函数,一定要成对使用,就像new和delete要成对使用。
    这一对成员函数可以保证:
    1)所有线程内的lock-unlock之间的内容不会同时执行;
    2)一个mutex对象只有一个锁,这个锁在谁手里,谁就能运行lock-unlock之间的内容;
    3)同一时刻,只有一个线程能够拿到一个mutex对象的锁,其他线程想要运行lock-unlock之间的内容必须等,等拿到锁;
    4)编程时,要确保共享数据在每个线程的lock-unlock之间,否则这个照样无约束,约束的不是数据,是线程,你得拿到锁,才能执行这部分的程序。
    示例:

    #include
    #include
    #include
    #include
    using namespace std;
    class A
    {
    private:
    	list data;
    	mutex my_mutex;
    public:
    	void input();
    	void output();
    }
    
    int main()
    {
    	A ta;//先实例化一个对象
    	//实例化两个线程
    	thread my_output_thread(&A::output, ref(ta));
    	thread my_input_thread(&A::input, ref(ta));
    	my_output_thread.join();
    	my_input_thread.join();
    	cout<<"主线程结束"< 
  2. std::unique_lock模板类
    unique_lock是一种模板类,它专门用来管理一个mutex对象,他俩一对一,unique_lock管理mutex的.lock()和.unlock()。最简单的unique_lock在构造函数中调用mutex的.lock(),在析构函数中调用mutex的.unlock(),所以不用再显式的去调用mutex的lock和unlock了。
    示例:

    //unique_lock和mutex要一对一,先有一个mutex
    std::mutex my_mutex;
    //{}内是unique_lock的作用域
    {
    	std::unique_lock uniLock1(my_mutex);
    	//...
    }
    //超出unique_lock的作用域,自然就会调用unique_lock的析构函数,也就调用了mutex的.unlock()
    

    std::defer_lock标识

    mutex my_mutex;
    //不带其他修饰的unique_lock,构造的时候会自动调用lock(),代码块结束,调用析够函数时候,自动调用unlock()
    unique_lock mylock(my_mutex);
    //带std::defer_lock,不会自动调用lock(),有lock, unlock, try_lock, release成员函数
    unique_lock mylock(my_mutex,defer_lock);
    //那岂不是跟自己用my_mutex一样了
    mylock.lock();
    mylock.unlock();
    mylock.try_lock();
    

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5690619.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存