您的位置:首页 > 编程语言 > C语言/C++

C++多线程编程

2018-03-23 10:04 197 查看

C++多线程demo

之前对多线程编程一直不了解,在编写工具时有一个工具使用了多线程编程,但在工具运行时,关闭工具会出现程序崩溃情况,所以了解了多线程编程的基础,写了一个生产者与消费者的demo,程序采用vs2015,C++11,VS2010不支持多线程编程,demo如下:

生产者与消费者

产品个数上限为10个,下限为0个,当产品为0时,产品不能被消费,只能生产,当产品个数超过10个,不能继续生产,只能被消费。

#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include<iostream>

class CThreadDemo
{
private:
std::mutex m_mtx; // 全局互斥锁.
std::condition_variable m_cv; // 全局条件变量,阻塞一个或多个线程,直到得到通知
int       m_nGen;//产品个数,共享变量、临界区

private:
void ProductThread() {
while (true) {
std::unique_lock <std::mutex> lck(m_mtx);//锁定共享变量
while (m_nGen >=10)
{
std::cout << "Product is enough!" << std::endl;
m_cv.wait(lck);//=0时,线程等待,通知消费者线程消费
}

m_nGen = ++m_nGen ;
printf("product %d\n", m_nGen);
lck.unlock();//解锁共享变量,能被其他线程使用
m_cv.notify_all();

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

void ConsumeThread() {
while (true) {
std::unique_lock <std::mutex> lck(m_mtx);//上锁
while (m_nGen <= 0) {
std::cout << "Product is not enough!" << std::endl;
m_cv.wait(lck);//<=0时,线程等待,直到大于0
}
m_nGen = --m_nGen;
printf("consume %d\n", m_nGen);
lck.unlock();//解锁
m_cv.notify_all();

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

//线程个数不要超过计算机核数的两倍
void Start() {
std::vector<std::thread> threads;
threads.clear();
for (int i = 0; i < 10; i++) {/* 生产者线程 */
threads.push_back(std::thread(&CThreadDemo::ProductThread, this));//参数传递
}
for (int i = 10; i < 18; i++) {/* 消费者线程 */
threads.push_back(std::thread(&CThreadDemo::ConsumeThread, this));
}
for (auto& t : threads) {/* 等待所有线程的退出 */
t.join();
}
}
};

int main()
{
CThreadDemo test;
test.Start();
return 0;
}


注意点

多线程最核心的问题在于资源竞争,例如控制台,控制台只有一个,可以有多个线程,但每个时间只能有一个线程能拥有控制台

关于detch( )和 join()表示线程的一种状态,必须在线程生命周期结束前确定是那种方式:

在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。

一个可结合的线程 (join) 能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的,join方式,等待启动的线程完成,才能继续向下执行。

一个分离的线程 (detach) 是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放,启动的线程在后台运行,当前的代码继续执行,不等待新线程的结束,是真正的后台运行。

参数传递:

如果需要将参数按引用传递,那要向下例所示那样,必须将参数用std::ref 或者std::ref进行封装。

std::thread p1(function,std::ref(a),"asdasd");


线程赋值:

std::thread p2=std::move(p1);


互斥量是用来保护多线程同时访问的共享数据,与lock()和unlock()搭配使用。分为std::mutex,最基本的数据量,std::time_mutex,带超时的独占互斥量,可以理解为定义获得锁的时间,std::recursive_mutex递归互斥量,防止死锁,std::recursive_time_mutex,是有两种情况。

std::condition_variable,配合std::unique_lock进行wait操作:

1.拥有条件变量的线程获取互斥锁

2.循环检查某个条件,如果条件不满足,则阻塞直到条件满足如果条件满足,则向下执行。

3.某个线程满足条件执行完之后调用notify_one或者notify_all
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: