首先谈谈对并发和并行的理解
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
并行:在操作系统中是指,一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。
因此并发和并行的区别就是,是否真正同时执行,并发是在一个时间段内几个任务都运行完毕,宏观上是一起执行,微观上顺序执行。并行是真正的多个任务同时执行。
互联网所说的高并发,也就是希望充分的利用CPU/内存等系统资源,让CPU尽可能不闲着
一、thread
#include <iostream>
#include <thread>
#include <unistd.h>
#include <error.h>
#define NUM_THREADS 10
using namespace std;
//void work(int& arg) {
void work(int arg) {
std::cout << "this is " << arg << std::endl;
};
int main()
{
thread threads[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; ++i){
//threads[i] = std::thread(work, std::ref(i));
threads[i] = std::thread(work, i);
}
for(int i=0; i < NUM_THREADS; ++i ){
threads[i].join();
}
return 0;
}
C++11新增了thread类,用法如上图,如果函数的参数是引用的话,实参需要添加std::ref()
注意:thread的类,不能设置线程某些属性,因此在项目中还是使用老版本的多线程函数
二、mutex
提供了lock_guard和unique_lock两种#include <iostream>
#include <thread>
#include <unistd.h>
#include <error.h>
#include <mutex>
#define NUM_THREADS 10
using namespace std;
std::mutex mtx;
//10个线程
void work(int& arg) {
std::lock_guard<std::mutex> lock(mtx);
arg++;
};
int main()
{
int rc = 0;
int sum = 0;
thread threads[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; ++i){
threads[i] = std::thread(work, std::ref(sum));
if (rc) {
return 1;
}
}
for(int i=0; i < NUM_THREADS; ++i ){
threads[i].join();
}
std::cout << "sum:" << sum << std::endl;
return 0;
}
#include <iostream>
#include <thread>
#include <unistd.h>
#include <error.h>
#include <mutex>
#define NUM_THREADS 10
using namespace std;
std::mutex mtx;
//10个线程
void work(int& arg) {
std::unique_lock<std::mutex> uni_lock(mtx); // 注意: 构造函数之后,就默认是lock的状态
arg++;
uni_lock.unlock();
};
int main()
{
int rc = 0;
int sum = 0;
thread threads[NUM_THREADS];
for(int i = 0; i < NUM_THREADS; ++i){
threads[i] = std::thread(work, std::ref(sum));
if (rc) {
return 1;
}
}
for(int i=0; i < NUM_THREADS; ++i ){
threads[i].join();
}
std::cout << "sum:" << sum << std::endl;
return 0;
}
lock_guard 不允许手动unlock/lock,性能消耗小,创建即加锁,作用域结束自动析构并解锁,无需手工解锁,不能中途解锁,必须等作用域结束才解锁,不能复制
unique_lock更加灵活,允许手动多次 unlock/lock 性能消耗大,默认是加锁状态
在实际项目当中,可以把要加锁的部分,单独做一个函数,用lock_guard,出了作用域自动解锁,控制了锁的粒度,性能最好
三、condition
注意:该条件变量只能搭配std::mutex或者std::unique_lock,无法使用lock_guard#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <condition_variable>
#define CUSTOMER_COUNT 2
#define PRODUCTER_COUNT 1
int g_num = 0;
std::condition_variable cv;
std::mutex mtx;
void* customer(void* arg)//消费者线程
{
int inum = 0;
inum = *(int *)arg;
while (1)
{
std::unique_lock<std::mutex> lock(mtx);
while (g_num == 0)
{
printf("\nwaiting start\n");
cv.wait(lock);//阻塞等待唤醒
printf("waiting end\n");
}
g_num--;//消费产品
}
pthread_exit(0);
}
void* producter(void* arg)//生产者线程
{
int inum = 0;
inum = *(int *)arg;
while (1)
{
std::unique_lock<std::mutex> lock(mtx);
printf("The num of g_num:%d\n", g_num);
g_num++;//生产产品
cv.notify_all(); //通知消费者
}
pthread_exit(0);
}
int main()
{
int i = 0;
pthread_t threadArray[CUSTOMER_COUNT + PRODUCTER_COUNT + 10];//线程数组
for (i = 0; i < PRODUCTER_COUNT; i++)//创建生产者线程
{
pthread_create(&threadArray[i], NULL, producter, (void*)&i);
}
for (i = 0; i < CUSTOMER_COUNT; i++)//创建消费者线程
{
pthread_create(&threadArray[i + CUSTOMER_COUNT], NULL, customer, (void*)&i);
}
for (i = 0; i < PRODUCTER_COUNT + CUSTOMER_COUNT; i++)//等待线程结束
{
pthread_join(threadArray[i], NULL);
}
return 0;
}
原理都是一致,生产者通知,消费者实时等待唤醒去消费