精华内容
下载资源
问答
  • C++ 多线程--STL 总结版 (详细)

    千次阅读 2019-10-28 17:35:31
    最近看C++ STL多线程部分,基本上看完了,现在就来做一下总结吧。 一、高级接口 1、多线程启动函数:std::async() 2、线程返回结果:std::future 3、共享变量:std::shared_future 二、低级接口 1、...

    最近在看C++ STL库的多线程部分,基本上看完了,现在就来做一下总结吧。

    目录

    一、高级接口

    二、低级接口

    三、互斥量与锁(Mutex & Lock)

             1、互斥量(Mutex):

             2、锁(Lock):

    四、条件变量(Condition Variable)

    一、高级接口   

    std::async() & std::future

    std::shared_future

    二、低级接口

    Class std::thread

    std::promise

    Class packaged_task

    三、互斥量与锁(Mutex & Lock)

    1、Class lock_guard

    2、Class unique_lock

    四、条件变量(Condition Variable)


    一、高级接口

             1、多线程启动函数:std::async()

             2、线程返回结果:std::future

             3、共享变量:std::shared_future

    二、低级接口

             1、多线程启动函数:Class std::thread

             2、线程返回结果:Promise

             3、线程池:Class packaged_task

    三、互斥量与锁(Mutex & Lock)

             1、互斥量(Mutex):

                      ①概念

                      ②作用

             2、锁(Lock):

                      ①概念

                      ②作用

    四、条件变量(Condition Variable)

                      ①概念

                      ②作用

     

    下面让我们逐个来学习一下吧!

    一、高级接口   

    std::async() & std::future

    1、async()的作用在于将其获取到的函数立即在一个新的线程内进行异步启动。也就是一个线程启动函数。其形式如下:

    std::aysnc(func1) //无参数形式
    

    2、向async()传递启动函数,并且传入启动函数的参数:

    void func1(int arg1,int arg2)
    {
        std::cout<<arg1<<std::endl;
        std::cout<<arg2<<std::endl;
    }
    
    std::aysnc(func1,arg1,arg2) //向函数func1传递arg1,arg2;

    3、std::aysnc()会返回一个std::future object类型的返回值,在std::future object中,我们可以取得线程返回值或异常信息。此外,std::future object类型的特化与线程函数的返回值一致。形式如下:

    void func1(int A = 0);
    int func2();
    
    
    int main()
    {
    	std::future<void> func1_res(std::async(print_A,10)); 
        //func1返回类型为void,future object的类型也为void
    
    	std::future<int> func2_res(std::async(print_B));
        //func2返回类型为int,future object的类型也为int
    }

    4、指定std::aysnc()的发射策略(launch strategy)

    std::async的策略主要有两个:

            1、std::launch::async  :  立即尝试启动异步调用,如果在此处无法进行调用时,会返回一个std::system_error

            2、std::launch::deferred : 延缓线程的启动,直到我们手动调用future::get()时,线程才会启动。

    示例如下:

    #include <future>
    #include <ctime>
    #include <iostream>
    #include <Windows.h>
    
    void func1()
    {
    	std::cout << "func1 start!" << std::endl;
    }
    void func2()
    {
    	std::cout << "func2 start!" << std::endl;
    }
    
    int main()
    {
        //f1在这里就启动了,输出func1 start!
    	std::future<void> f1(std::async(std::launch::async, func1));
        //f2在这里由于发射策略的原因,并没有启动
    	std::future<void> f2(std::async(std::launch::deferred, func2));
    	Sleep(3000);
    	std::cout << "3 seconds later!" << std::endl;
        //三秒之后,由于调用future::get(),线程f2启动,输出func2 start!
    	f2.get();
    	return 0;
    }

    std::shared_future

    shared_future 简单说来,其实就是一个可以多次调用 其成员函数get()的object。

    由于std::future的成员函数get()只能够调用一次,第二次调用的时候会出现不可预期的行为(实际上就会报错或者完全不会有任何动作)。但是,很多时候,我们希望一个线程可以被多个线程利用,这个时候,std::share_future就横空出世了!

    #include <future>
    #include <iostream>
    #include <string>
    #include <thread>
    #include <stdexcept>
    #include <exception>
    
    using namespace std;
    int func1()
    {
    	std::cout << "Read Number: ";
    	int num;
    
    	std::cin >> num;
    	if (!std::cin)
    	{
    		throw runtime_error("no number read");
    	}
    	return num;
    }
    
    
    void addOne(std::shared_future<int> SfObject)
    {
    	int num = SfObject.get();
    	num += 1;
    	std::cout << num << std::endl;
    }
    
    int main()
    {
    	std::shared_future<int> f = std::async(func1);
    	auto f1 = std::async(addOne, f);
    	auto f2 = std::async(addOne, f);
    
    	f1.get();
    	f2.get();
    	return 0;
    }

    可以看到上面这段代码中,std::shared_future<int> f 的成员函数 std::get()被多次调用。假如我们将share_future object 换为futureobject时,甚至无法通过编译。

     

    二、低级接口

    Class std::thread

    Class std::thread的调用接口与std::async()颇为显示,一起看一下下面这个实例:

    #include <iostream>
    #include <thread>
    
    
    void Print(int num)
    {
    	std::cout << "this is thread: "<< num << std::endl;
    }
    
    
    int main()
    {
    
    	std::thread t1(Print, 1); //创建线程1
    	std::thread t2(Print, 2); //创建线程2
    	t1.join(); //等待线程1结束
    	t2.join(); //等待线程2结束
    	std::cout << "this is  main thread "<< std::endl;
    	return 0;
    }

    可以看到,在线程创建和传参上,Class thread  和 std::async()的手法都颇为类似。只不过一个是类,一个是函数。

    但是,两者也有颇多地方有较大差异:

    1、Class thread 没有发射策略,只要我们实例化Class thread的对象,系统就会尝试启动目标函数,如果无法启动目标函数,就会抛出std::system_error并携带差错码resource_unavailable_try_again。

    2、Class thread并不提供处理线程结果的接口

    3、必须对线程的状态进行声明,等待其结束(join())或直接卸载(detach())

    4、如果main()函数结束了,所有线程会被直接终止

     

    std::promise

    待补充。。

     

    Class packaged_task

    Class packaged_task实现了运行我们自由控制启动线程的启动时间,可以用于实现线程池。

    让我们直接来看一个例子吧:

    #include <iostream>
    #include <thread>
    #include <string>
    #include <chrono>
    #include <future>
    #include <Windows.h>
    
    void func1()
    {
    	std::cout << "creating thread……" << std::endl;
    }
    
    
    int main()
    {
    	std::packaged_task<void()> task(func1);  //这里创建thread task,但是不会立即启动线程
    	std::cout << "Sleep for 3 seconds" << std::endl;
    	Sleep(3000); //sleep3秒,当然,这里可以改成任何你需要的操作
    	task(); //3秒后启动线程
    	return 0;
    }

    好的到目前为止,关于线程的启动和创建过程的内容到这里就基本结束了,接下来,我们以一张图作为这部分的结束。

                

                                                                     (图源:《C++标准库》(侯捷译)

     

    三、互斥量与锁(Mutex & Lock)

    首先,我们得先理解为什么会出现互斥量这种需求。其实,在上面,有一段代码是在线程中输出一段字符串,我们看看看到,由于线程的启动都是同时的,所以两个不同的线程会同时对一个命令窗口输出字符,这样就会导致一种不可预计的情况,如图:

                                                                  

    可以看到,字符的输出并没有按照我们的预期。那么,当我们有一个变量mutex,同时在多个线程中会被使用,其中线程A在线程B对mutex进行修改的过程中,同时又对mutex进行修改,那么,不可预期的事情便会发生。

    所以,我们需要互斥量的出现。同时,我们需要对会被多个线程调用的变量的修改过程进行上锁(Lock),保证上锁过程中线程对资源的独占,才能避免多线程同时对某个变量进行修改,而导致不可预期的事情发生。

    还是以上面的字符输出代码为例,我们要怎么修改才能得到我们预期的输出呢? 答案很简单,那就是对字符输出的过程进行上锁(lock),输出结束时解锁(unlock)。看代码吧!

    #include <iostream>
    #include <thread>
    #include <mutex>
    
    std::mutex mut;//声明互斥量
    
    void Print(int num)
    {
    	mut.lock();//对输出过程进行上锁
    	std::cout << "this is thread: "<< num << std::endl;
    	mut.unlock();//解锁
    }
    
    
    int main()
    {
    
    	std::thread t1(Print, 1);
    	std::thread t2(Print, 2);
    	t1.join();
    	t2.join();
    	std::cout << "this is  main thread "<< std::endl;
    	return 0;
    }

    这样修改之后,就能得到我们想要得到的输出效果:

    就是这样,我们对多线程处理的公共部分,进行上锁,使得线程独占资源,便可以使得资源在线程修改的这段时间内不被别的线程使用。但是,随着应用锁(Lock)的场景越来越多,我们也有了更多不同的需求,所以就发展出了各种不同的锁。同时也会出现一些问题。

                                                                                       (各种Mutex及其功能)

                                                                                 (Mutex Class 的操作函数)

    接下来我们讲一下几个重要的Lock的方式

    1、Class lock_guard

    最简单的锁形式就是Mutex.Lock(),这个方法简单好用,但是有很多时候,人们会忘记将其解锁(Mutex.unlock()),所以出现了lock_guard的这种自动解锁的方法。Class lock_guard是在声明时,自动上锁,在离开作用域之后自动析构解锁。

    我们看一下接口:

    #include <iostream>
    #include <thread>
    #include <mutex>
    
    std::mutex mut;
    
    void Print(int num)
    {
    	std::cout << "this is thread_unlock: " <<num<< std::endl;//未上锁
    	{
    		std::lock_guard<std::mutex> lg(mut);//上锁
    		std::cout << "this is thread: " << num << std::endl;
    	}//超出作用域,自动解锁
    }
    
    
    int main()
    {
    
    	std::thread t1(Print, 1);
    	std::thread t2(Print, 2);
    	t1.join();
    	t2.join();
    	std::cout << "this is  main thread " << std::endl;
    	return 0;
    }

    上面的代码在没有上锁的字符输出过程中就串行了。

    2、Class unique_lock

    相对于Class lock_guard 来说,Class unique_lock 的特殊之处在于,可以让我们指定“何时”以及“如何”锁定和结果Mutex,此外,在Class unique_lock中,我们甚至可以用owns_lock()或bool()来查询目前Mutex是否会被锁住。

     

    四、条件变量(Condition Variable)

    在多线程的实际应用中,我们总有需要某个线程等待另外一个线程的处理结果。当然,最简单粗暴的方法自然就是设置一个全局的bool ReadyFlag,在 ReadyFlag 状态发生变化是,线程进行处理。

    但是这样做有比较明显的弊端,举个栗子来说明这个问题吧~

    bool ReadyFlag{False};
    
    
    void thread1()
    {
        …………//大段处理代码,需要一定时间。
        ReadyFlag = true; //满足条件,ReadyFlag状态变为true
    }
    
    void thread2()
    {
        if(ReadyFlag)
        {
            …………//大段处理代码
        }
    }

    可以看到在thread1函数中,当我们处理大段代码时,thread2中一直针对目标条件进行轮询,这样会耗费大量的资源。

    实际上,我们希望得到的效果是: thread1 在处理完大量操作后,ReadyFlag的状态改变,达到满足 thread2 的启动条件,然后 thread1 将thread2 进行唤醒。

    这就是条件变量(Condition Variable)存在的意义。

    先来看一下Class Condition Variable的成员函数:

    下面我们来看一个例子实际体会一下吧。

    #include <condition_variable>
    #include <mutex>
    #include <future>
    #include <iostream>
    
    bool readyFlag;
    std::mutex readyMutex;
    std::condition_variable readyCondVar;
    
    void thread1()
    {
    	std::cout << "<Return>" << std::endl;
    	std::cin.get();
    	{
    		std::lock_guard<std::mutex> lg(readyMutex);
    		readyFlag = true;
    	}
    	readyCondVar.notify_one();//条件成立,唤醒等待者
    }
    
    
    void thread2()
    {
    	{
    		std::unique_lock<std::mutex> ul(readyMutex);
    		readyCondVar.wait(ul, [] {return readyFlag; });//等待条件变量的状态
    	}
    
    	std::cout << "Done!" << std::endl;
    }
    
    int main()
    {
    	auto f1 = std::async(std::launch::async, thread1);
    	auto f2 = std::async(std::launch::async, thread2);
    	return 0;
    }

    使用条件变量(Condition Variable)进行这样的线程之间的通信等待,就可以放弃轮询操作,节省CPU的资源和时间。

     

    好的,到这里为止,我对于C++多线程的总结就做到这里吧~感觉写了很多了。但是实际上,这些都只是一些皮毛,只能教会我们如何去使用多线程,对于多线程的应用和各种问题(比如我们常听到的“死锁”问题等)都没有深入探究,这些等我以后有空了再来谈吧。各位,如果看到有啥错误的地方,也请大家都能指出来,共同进步~

    此外,我还推荐大家有空想学习多线程的,可以去看看《C++标准库》(侯捷译)这本书,里面对多线程的调用有极为详细的讲解。谢谢大家,看到这里。

    展开全文
  • windows核心编程-C/C++标准库多线程

    千次阅读 2016-12-02 09:45:10
    VC++标准库做了多线程安全扩展 2、要利用这些扩展就需要使用VC++扩展库提供的创建线程函数_beginthread,_beginthradEx等 函数来替代Windows的原始API--CreateThread 3、因为这些创建函数内部考虑了多线程...

    1、由于历史原因,标准C/C++库在开始时并没有正对多线程做考虑(比如使用了一些全局变量),

    在VC++中对标准库做了多线程安全扩展

    2、要利用这些扩展就需要使用VC++扩展库提供的创建线程函数_beginthread,_beginthradEx等

    函数来替代Windows的原始API--CreateThread

    3、因为这些创建函数在内部考虑了多线程安全初始化C/C++标准库,使用这些替代函数创建的线程调用

    C/C++时将时多线程安全的(比如:利用TLS等特性改进全局变量)

    4、如果只是API的话,那么不存在什么问题(GRSLib库是一个基本不使用C/C++标准库的纯API式的库,

    最终是否使用了C/C++标准库由调用者子集决定,但是其线程创建还是使用了_beginthreadex函数)

    5、但是若需要调用C/C++库函数的话都建议使用扩展的创建函数替代品(建议使用_beginthreadex)


    使用C++类非静态成员函数创建线程

    1、如果C++类的非晶态成员是__stdcall调用约定的,那么调用次成员函数时,即使this指针也会入栈

    2、而CreateThread(包括_beginthread和_beginthreadex)方法都会传递一个线程函数参数

    3、利用这一特征可以将this指针传入,并将指向成员函数的指针当作线程入口参数(适当做下函数指针的

    强制类型转换)


    C++类封装线程的问题

    因为线程C++对象和实际代表的生命周期的不同,所以有可能在对象已经析构之后,线程本身还在运行,还可能调用

    到线程对象的方法

    因此一般的策略时将C++的线程对象分配到堆上,并当线程函数结束的时候,由线程对象内部自己来释放自己


    #include<windows.h>
    #include<tchar.h>
    #include<strsafe.h>
    
    #include<process.h>
    
    #define GRS_USEPRINTF() TCHAR pBuf[1024]={}
    #define GRS_PRINTF(...)\
    	StringCchPrintf(pBuf, 1024, __VA_ARGS__); \
    	WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pBuf, lstrlen(pBuf), NULL, NULL);
    
    class ThreadClass
    {
    protected:
    	HANDLE m_hThread;
    	DWORD m_dwThreadID;
    public:
    	ThreadClass(BOOL bCreate = TRUE)
    		:m_hThread(NULL)
    		,m_dwThreadID(0)
    	{
    		GRS_USEPRINTF();
    		GRS_PRINTF(_T("ThreadClass对象[A:0x%08x]初始化在线程[ID:0x%x]中\n"),
    			this,GetCurrentThreadId());
    		if (bCreate)
    		{
    			CreateThread();
    		}
    	}
    	virtual ~ThreadClass()
    	{
    
    	}
    protected :
    	UINT __stdcall ThreadProc(LPVOID lpParameter)
    	{
    		if (InitThread())
    		{
    			Run();
    		}
    		return ExitThread();
    	}
    public:
    	BOOL CreateThread(DWORD dwStackSize = 0)
    	{
    		typedef UNIT (__stdcall *StdProc)(LPVOID);
    		typedef UNIT (__stdcall ThreadClass::*ThreadObject)(LPVOID);
    		ThreadObject pThis = &ThreadClass::ThreadProc;
    
    		GRS_USEPRINTF();
    		m_hThread = (HANDLE)_beginthreadex(NULL, dwStackSize,
    			*(StdProc*)&pThis, this, CREATE_SUSPENDED, (UINT*)&m_dwThreadID); //指向类成员函数的指针
    
    		if (-1L == (LONG)m_hThread)
    		{
    			GRS_PRINTF(_T("_beginthreadex发生错误"));
    			return FALSE;
    		}
    		ResumeThread(m_hThread);
    		return -1L != (LONG)m_hThread;
    	}
    public:
    	virtual BOOL InitThread()
    	{
    		GRS_USEPRINTF();
    		GRS_USEPRINTF(_T("ThreadClass对象[A:0x%08x]线程[H:0x%08x ID:0x%x]初始化\n"),
    			this,m_hThread,m_dwThreadID);
    		return TRUE;
    
    	}
    	virtual BOOL Run()
    	{
    		GRS_USEPRINTF();
    		GRS_USEPRINTF(_T("ThreadClass对象[A:0x%08x]线程[H:0x%08x ID:0x%x]运行\n"),
    			this, m_hThread, m_dwThreadID);
    		return TRUE;
    
    	}
    	virtual BOOL ExitThread()
    	{
    		GRS_USEPRINTF();
    		GRS_USEPRINTF(_T("ThreadClass对象[A:0x%08x]线程[H:0x%08x ID:0x%x]退出\n"),
    			this, m_hThread, m_dwThreadID);
    		return TRUE;
    
    	}
    };
    
    int _tmian()
    {
    	ThreadClass thd;
    	_tsystem(_T("PAUSE"));
    	return 0;
    }
    


    展开全文
  • Python标准库08 多线程与同步 (threading包)

    千次阅读 多人点赞 2020-11-12 08:48:00
    Python主要通过标准库中的threading包来实现多线程当今网络时代,每个服务器都会接收到大量的请求。服务器可以利用多线程的方式来处理这些请求,以提高对网络端口的读写效率。Py...

    Python主要通过标准库中的threading包来实现多线程。在当今网络时代,每个服务器都会接收到大量的请求。服务器可以利用多线程的方式来处理这些请求,以提高对网络端口的读写效率。Python是一种网络服务器的后台工作语言 (比如豆瓣网),所以多线程也就很自然被Python语言支持。

    (关于多线程的原理和C实现方法,请参考我之前写的Linux多线程与同步,要了解race condition, mutex和condition variable的概念)

     

    多线程售票以及同步

    我们使用Python来实现Linux多线程与同步文中的售票程序。我们使用mutex (也就是Python中的Lock类对象) 来实现线程的同步:

     

    # A program to simulate selling tickets in multi-thread way
    # Written by Vamei
    
    
    import threading
    import time
    import os
    
    
    # This function could be any function to do other chores.
    def doChore():
        time.sleep(0.5)
    
    
    # Function for each thread
    def booth(tid):
        global i
        global lock
        while True:
            lock.acquire()                # Lock; or wait if other thread is holding the lock
            if i != 0:
                i = i - 1                 # Sell tickets
                print(tid,':now left:',i) # Tickets left
                doChore()                 # Other critical operations
            else:
                print("Thread_id",tid," No more tickets")
                os._exit(0)              # Exit the whole process immediately
            lock.release()               # Unblock
            doChore()                    # Non-critical operations
    
    
    # Start of the main function
    i    = 100                           # Available ticket number 
    lock = threading.Lock()              # Lock (i.e., mutex)
    
    
    # Start 10 threads
    for k in range(10):
        new_thread = threading.Thread(target=booth,args=(k,))   # Set up thread; target: the callable (function) to be run, args: the argument for the callable 
        new_thread.start()                                      # run the thread
    

    我们使用了两个全局变量,一个是i,用以储存剩余票数;一个是lock对象,用于同步线程对i的修改。此外,在最后的for循环中,我们总共设置了10个线程。每个线程都执行booth()函数。线程在调用start()方法的时候正式启动 (实际上,计算机中最多会有11个线程,因为主程序本身也会占用一个线程)。Python使用threading.Thread对象来代表线程,用threading.Lock对象来代表一个互斥锁 (mutex)。

    有两点需要注意:

    • 我们在函数中使用global来声明变量为全局变量,从而让多线程共享i和lock (在C语言中,我们通过将变量放在所有函数外面来让它成为全局变量)。如果不这么声明,由于i和lock是不可变数据对象,它们将被当作一个局部变量(参看Python动态类型)。如果是可变数据对象的话,则不需要global声明。我们甚至可以将可变数据对象作为参数来传递给线程函数。这些线程将共享这些可变数据对象。

    • 我们在booth中使用了两个doChore()函数。可以在未来改进程序,以便让线程除了进行i=i-1之外,做更多的操作,比如打印剩余票数,找钱,或者喝口水之类的。第一个doChore()依然在Lock内部,所以可以安全地使用共享资源 (critical operations, 比如打印剩余票数)。第二个doChore()时,Lock已经被释放,所以不能再去使用共享资源。这时候可以做一些不使用共享资源的操作 (non-critical operation, 比如找钱、喝水)。我故意让doChore()等待了0.5秒,以代表这些额外的操作可能花费的时间。你可以定义的函数来代替doChore()。

     

    OOP创建线程

    上面的Python程序非常类似于一个面向过程的C程序。我们下面介绍如何通过面向对象 (OOP, object-oriented programming,参看Python面向对象的基本概念和Python面向对象的进一步拓展) 的方法实现多线程,其核心是继承threading.Thread类。我们上面的for循环中已经利用了threading.Thread()的方法来创建一个Thread对象,并将函数booth()以及其参数传递给改对象,并调用start()方法来运行线程。OOP的话,通过修改Thread类的run()方法来定义线程所要执行的命令。

     

    我们自己定义了一个类BoothThread, 这个类继承自thread.Threading类。然后我们把上面的booth()所进行的操作统统放入到BoothThread类的run()方法中。注意,我们没有使用全局变量声明global,而是使用了一个词典monitor存放全局变量,然后把词典作为参数传递给线程函数。由于词典是可变数据对象,所以当它被传递给函数的时候,函数所使用的依然是同一个对象,相当于被多个线程所共享。这也是多线程乃至于多进程编程的一个技巧 (应尽量避免上面的global声明的用法,因为它并不适用于windows平台)。

    上面OOP编程方法与面向过程的编程方法相比,并没有带来太大实质性的差别。

     

    其他

    threading.Thread对象:我们已经介绍了该对象的start()和run(), 此外:

    • join()方法,调用该方法的线程将等待直到改Thread对象完成,再恢复运行。这与进程间调用wait()函数相类似。

     

    下面的对象用于处理多线程同步。对象一旦被建立,可以被多个线程共享,并根据情况阻塞某些进程。请与Linux多线程与同步中的同步工具参照阅读。

    threading.Lock对象: mutex, 有acquire()和release()方法。

    threading.Condition对象: condition variable,建立该对象时,会包含一个Lock对象 (因为condition variable总是和mutex一起使用)。可以对Condition对象调用acquire()和release()方法,以控制潜在的Lock对象。此外:

    • wait()方法,相当于cond_wait()

    • notify_all(),相当与cond_broadcast()

    • nofify(),与notify_all()功能类似,但只唤醒一个等待的线程,而不是全部

    threading.Semaphore对象: semaphore,也就是计数锁(semaphore传统意义上是一种进程间同步工具,见Linux进程间通信)。创建对象的时候,可以传递一个整数作为计数上限 (sema = threading.Semaphore(5))。它与Lock类似,也有Lock的两个方法。

    threading.Event对象: 与threading.Condition相类似,相当于没有潜在的Lock保护的condition variable。对象有True和False两个状态。可以多个线程使用wait()等待,直到某个线程调用该对象的set()方法,将对象设置为True。线程可以调用对象的clear()方法来重置对象为False状态。

    作者:Vamei 出处:http://www.cnblogs.com/vamei

    亲,需要你的“分享”“在看”

    IT入门 感谢关注

    程序员题库→

    程序员用的单词表→

    练习地址:www.520mg.com/it

    展开全文
  • C++ 标准库中线程安全

    千次阅读 2018-04-16 14:07:16
    线程安全规则应用到标准 C++ 库中的所有类,这也包括 shared_ptr,如下所述。 有时提供更强的保证(例如,如下所述的标准 iostream 对象和专门用于多线程的类型,如 中的类型)。 从多个线程读取某个对象时,该对象...

    线程安全规则应用到标准 C++ 库中的所有类,这也包括 shared_ptr,如下所述。 有时提供更强的保证(例如,如下所述的标准 iostream 对象和专门用于多线程的类型,如 中的类型)。

    多个线程读取某个对象时,该对象是线程安全的。
    例如,给定对象 A,可安全地同时从线程 1 和线程 2 读取 A。

    如果要通过某个线程写入到对象,则必须保护相同线程或其他线程上所有对该对象的读取和写入
    例如,给定对象 A,如果线程 1 将写入到 A,则必须阻止线程 2 读取或写入 A。

    注意:即使另一个线程正在读取或写入同一类型的其他实例,本线程也可以安全地读取和写入该类型的某个实例。
    例如,给定同一类型的对象 A 和 B,在线程 1 中写入 A 的同时可以安全地在线程 2 中读取 B。

    shared_ptr

    即使对象是共享所有权的副本,多个线程也可以同时读取和写入不同的 shared_ptr 对象。

    这篇文章讲的很详细shared_ptr线程安全性分析

    iostream

    标准 iostream 对象 cincoutcerrclogwcinwcoutwcerrwclog 遵循与其他类相同的规则,但存在此例外:可以安全地从多个线程写入一个对象。 例如,可以将线程 1 和线程 2 同时写入 cout。 但是,此操作可能会导致两个线程的输出相混合。

    展开全文
  • C++类中使用pthread实现多线程

    千次阅读 2017-07-28 21:11:06
    现在pthread的api已经相当完善,使用其实现多线程难度不大,但是值得注意的一点是当想中使用pthread,调用pthread_create函数时,传入的运行函数,也就是下面这个原型的第三个参数void * ( * start_routine) ...
  • OpenCV使用pthread实现多线程加速处理图像(C++)

    万次阅读 多人点赞 2018-08-21 19:41:44
    OpenCV使用pthread实现多线程加速处理图像 【尊重原创,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/81912704 目录 OpenCV使用pthread实现多线程加速处理图像 1.pthread多线程加速 2....
  • UI界面程序使用到多进程与多线程是很常见的场景,有时候我们需要将一些耗时的操作放在其他的线程或者进程,避免卡死主线程。而且利用多线程加Qt的信号槽机制我们可以子进程实现事件监听,实时监测进程间...
  • C++标准线程库之入门

    千次阅读 2018-10-21 20:25:58
    自c++11版本后,标准库也提供了对线程的支持。虽然大多场合还是使用其他的三方线程库,如:boost::thread, QThread等,但是学习下还是有必要的。 1. std::thread简介 ***std::thread***类即创建子线程的类,定义...
  • 《VS配置pthread多线程库

    千次阅读 2018-05-16 10:52:03
    POSIX标准包含了一系列用于多线程编程的API(pthread),除了win32之外,许多现代的操作系统都渐渐开始支持pthread。我的配置:windows10+VS2010一、下载pthread多线程库1、pthread多线程库下载地址:ftp://...
  • C++中使用openmp进行多线程编程

    万次阅读 多人点赞 2015-11-13 15:53:40
    声明:本文是基于Joel Yliluoma写的Guid into OpenMP:Easy multithreading programming for C++而写的,基本是按照自己的理解,用...对于C++而言,当我们需要使用多线程时,可以使用boost::thread或者自从C++ 11开始
  • 1. 有时候需要使用vector 或 map作为多线程的共享变量, map是tree结构, 读和写方法都不是线程安全的, 即同时读写会有崩溃的现象. 2. std::vector直观来说只用push_back和[] 下标访问操作应该没问题,push_back往后边...
  • Boost.Asio 有两种支持多线程的方式,第一种方式比较简单:在多线程的场景下,每个线程都持有一个io_service,并且每个线程都调用各自的io_service的run()方法。  另一种支持多线程的方式:全局只分配一个io_...
  • 我们可以直接从python的标准库中引入多线程模块threading: import threading from queue import Queue import time 同时你可以通过 target 参数定义线程调用的函数,通过 args 为该函数传参,用 start ...
  • C++多线程中的join, detach, joinable

    千次阅读 2020-02-01 16:08:30
    thread是C++11提供多线程编程的模块,使用的时候需要包含<thread>头文件。 首先我们先来看一下简单的hello world的多线程的代码(win10下vs2019) 这个创建的方式就是以函数作为一个入口,创建了一个...
  • C语言多线程操作

    千次阅读 2019-11-27 22:39:38
    C语言多线程操作 目录 C语言多线程 创建线程 终止线程 注意 信号量机制 参考博文: 返回目录 C语言多线程 多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般...
  • 线程库

    千次阅读 2018-04-11 16:28:06
    多线程 一. 什么是线程 线程是进程可执行代码流的序列,它被操作系统调用,并处理器或内核上运行。所有进程都有一个主线程,主线程是进程的控制流或执行路线。线程分为用户线程和系统线程,线程创建,维护...
  • t 甚或几 p 的数据的数据库系统,到手机上的一个有良好用户响应能力的 app,为了充分利用每个 CPU 内核,都会想到是否可以使用多线程技术。这里所说的“充分利用”包含了两个层面的意思,一
  • OpenCV视频流的C++多线程处理方式

    千次阅读 2021-01-14 11:20:08
    之前有写过一篇文章Python环境下OpenCV视频流的多线程处理方式,上面简单记录了如何使用Python实现对OpenCV视频流的多线程处理。简单来说,目标检测等任务,如果视频流的捕获、解码以及检测都同一个线程,...
  • nodejs中使用多线程编程的方法实例

    千次阅读 2015-05-26 23:50:28
    这篇文章主要介绍了nodejs中使用多线程编程的方法实例,本文使用nodejs addon借助c/c++的能力扩展nodejs多线程编程,需要的朋友可以参考下 以前的博文别说不可能,nodejs中实现sleep中,我向大家介绍了nodejs ...
  • 浅谈 Python 多线程

    千次阅读 2019-09-28 23:05:03
    大家好,我是 Rocky0429,今天我来写一下 Python 多线程正式开始之前,我先用比较通俗的语言给大家介绍几个比较重要的概念。 首先是「并发编程」。「并发」其实我们的生活随处可见,比如我们去银行存钱...
  • Python多线程编程

    千次阅读 多人点赞 2019-02-28 11:46:07
    在多线程(multithreaded, MT)编程出现之前,计算机程序的执行是由单个步骤序列组成的,该序列主机的 CPU 按照同步顺序执行。无论是任务本身需要按照步骤顺序执行,还是整个程序实际上包含多个子任务,都需要...
  • 线程安全规则应用到标准 C++ 库中的所有类,这也包括 shared_ptr,如下所述。 有时提供更强的保证(例如,如下所述的标准 iostream 对象和专门用于多线程的类型,如 中的类型)。 从多个线程读取某个对象时,该对象...
  • 浅谈C++多线程(一)

    万次阅读 多人点赞 2019-03-23 23:11:23
    同步互斥原理以及多进程和多线程中实现同步互斥的两种方法 Qt多线程应用 引入 传统的C++(C++98)并没有引入线程这个概念。linux和unix操作系统的设计采用的是多进程,进程间的通信十分方便,同时进程之间...
  • Python多线程入门指南

    万次阅读 多人点赞 2017-02-25 21:48:54
    python的标准库中提供了线程安全的队列,基于FIFO(先进先出)实现,可以方便的帮助我们实现线程间的消息传递,使用非常简单,其原理也不难,用一张简单的图展示: 另外,凡是符合该种结构的多线程通信过程我们称之为...
  • 多线程开发需要注意的问题

    千次阅读 2017-03-21 23:04:34
    多线程开发 Linux 平台上已经有成熟的 Pthread 支持。其涉及的多线程开发的最基本概念主要包含三点:线程,互斥锁,条件。其中,线程操作又分线程的创建,退出,等待 3 种。互斥锁则包括 4 种操作,分别是创建,...
  • Linux创建多线程实例pthread_create()

    千次阅读 2020-04-15 22:24:58
    文章目录编程环境:线程:已经程序是多线程构成:pthread_create():写一个例子:例子一:例子二:下载地址: 简 述: 前面几篇,学习了 Linux 下多进程使用 fork() 分析的其构造和原理;这里进一步,探究一下如何...
  • 线程以及pthread使用

    千次阅读 2019-06-09 15:01:34
    一.什么是线程 你可以想象你一边听歌一边打游戏,如果是操作系统会怎么做呢?先执行 ListenMusic 再执行...线程是 CPU 调度的最小执行单位,你可以创建一个线程用于ListenMusic,再创建一个线程去PlayGame,这样操...
  • python多线程

    千次阅读 2018-06-27 14:25:20
    一、概念 单线程:串行执行,即执行流程一条线上 多线程:并行执行,即执行流程多条线上多任务可以由多进程完成,也可以由一个进程的多个...二、python中多线程的库介绍: thread 和threading两个标准库 ...
  • Python多线程(模拟火车站售票)

    千次阅读 2019-04-27 16:56:39
    Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。 我们使用threading这个高级模块,模拟火车站卖票,如果不加锁,卖出同一张票: import ...
  • C++多线程并发(一)--- 线程创建与管理

    万次阅读 多人点赞 2020-03-16 22:21:32
    应用程序中使用并发的原因主要有两个:关注点分离和性能。事实上,甚至可以说它们差不多是使用并发的唯一原因;当你观察的足够仔细时,一切其他因素都可以归结到这两者之一(或者可能是二者兼有)。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 217,407
精华内容 86,962
关键字:

如何在多线程中使用标准库