多线程问题C++

关于多线程,一直都是一知半解,今天又看了些相关知识,总结下:

1.过去写的单片机裸跑的程序,其实也属于多线程的,用智能电表中的固件做个比方。

void main(void){

initilize_para();   //基础参数的初始化
.....
while
{

      DealWith485Com();      //485通信
      DealWithEnergy();        //电量数据处理
      DealWithIRCOM();       //红外通信任务
        ......                                     //其他任务

}

}

以上,在while{}循环中,所列包括3个“线程”处理,线程1在运行完之后运行线程2,线程2运行完进入线程3....,后面依次,此类我觉得也可称之“线程”。由于不必存在同时处理的问题,因此不存在争抢同一共享区域的问题。

2.通常意义上的多线程,通过时间片分配各个线程的运行时间,表面上看似可以同时运行。通过creat_thread()方式创建线程,线程运行完毕则退出。存在不同线程争抢共享资源的问题。以C++11实现简单生产者消费者模式说明。

#include "stdafx.h"
#include <thread>
#include <mutex>
#include <deque>
#include <vector>
#include <condition_variable>

class CThreadDemo
{
private:
    std::deque<int> m_data;
    std::mutex m_mtx; // 全局互斥锁.
    std::condition_variable m_cv; // 全局条件变量.
    int       m_nGen;

扫描二维码关注公众号,回复: 3591025 查看本文章

private:
    void ProductThread(){
        printf("PTr");
        while (true){
            std::unique_lock <std::mutex> lck(m_mtx);
            m_nGen = ++m_nGen % 1000;
            printf("product %d\n", m_nGen);
            m_data.push_back(m_nGen);
            lck.unlock();
            m_cv.notify_all();

            /* 等待1S */
            std::chrono::milliseconds dura(1000);
            std::this_thread::sleep_for(dura);
        }
    }

    void ConsumeThread(){
        printf("CTr");
        while (true){
            std::unique_lock <std::mutex> lck(m_mtx);
            while (m_data.empty()){
                m_cv.wait(lck);
            }
            int nData = m_data.front();
            m_data.pop_front();
            printf("consume %d\n", nData);
            lck.unlock();

            /* 等待2S */
            std::chrono::milliseconds dura(2000);
            std::this_thread::sleep_for(dura);
        }
    }
public:
    CThreadDemo(){
        m_data.clear();
        m_nGen = 0;
    }

    void Start(){
        std::vector<std::thread> threads;
        threads.clear();
        for (int i = 0; i < 5; i++){/* 生产者线程 */
            threads.push_back(std::thread(&CThreadDemo::ProductThread, this));
        }
        for (int i = 5; i < 10; i++){/* 消费者线程 */
            threads.push_back(std::thread(&CThreadDemo::ConsumeThread, this));
        }
        for (auto& t : threads){/* 等待所有线程的退出 */
            t.join();
        }
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    CThreadDemo test;
    test.Start();
    return 0;

}

实现了一个简单的生产者-消费者模式,生产者每1S将一个数值放到双向队列中,消费者每2S从双向队列中取出数据。主要介绍下std::condition_variable的使用。

<condition_variable>是C++标准程序库中的一个头文件,定义了C++11标准中的一些用于并发编程时表示条件变量的类与方法等。

条件变量是并发程序设计中的一种控制结构。多个线程访问一个共享资源(或称临界区)时,不但需要用互斥锁实现独享访问以避免并发错误(称为竞争危害),在获得互斥锁进入临界区后还需要检验特定条件是否成立:

(1)、如果不满足该条件,拥有互斥锁的线程应该释放该互斥锁,把自身阻塞(block)并挂到(suspend)条件变量的线程队列中

(2)、如果满足该条件,拥有互斥锁的线程在临界区内访问共享资源,在退出临界区时通知(notify)在条件变量的线程队列中处于阻塞状态的线程,被通知的线程必须重新申请对该互斥锁加锁。

std::condition_variable类的成员函数:

(1)、构造函数:仅支持默认构造函数,拷贝、赋值和移动(move)均是被禁用的。

(2)、wait:当前线程调用wait()后将被阻塞,直到另外某个线程调用notify_*唤醒当前线程;当线程被阻塞时,该函数会自动调用std::mutex的unlock()释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动调用std::mutex的lock()。wait分为无条件被阻塞和带条件的被阻塞两种。

无条件被阻塞:调用该函数前,当前线程应该已经对unique_lock<mutex> lck完成了加锁。所有使用同一个条件变量的线程必须在wait函数中使用同一个unique_lock<mutex>。该wait函数内部会自动调用lck.unlock()对互斥锁解锁,使得其他被阻塞在互斥锁上的线程恢复执行。使用本函数被阻塞的当前线程在获得通知(notified,通过别的线程调用 notify_*系列的函数)而被唤醒后,wait()函数恢复执行并自动调用lck.lock()对互斥锁加锁。

带条件的被阻塞:wait函数设置了谓词(Predicate),只有当pred条件为false时调用该wait函数才会阻塞当前线程,并且在收到其它线程的通知后只有当pred为true时才会被解除阻塞。因此,等效于while (!pred())  wait(lck).

猜你喜欢

转载自blog.csdn.net/zhubeifen_521/article/details/82784428
今日推荐