一 创建线程
#include <thread>
int num = 0;
void showNum(string str)
{
while (num < 10)
{
cout << str << "num:" << num << endl;
num++;
}
}
int main()
{
thread t1(showNum, "线程一");//第一个参数是执行的函数,后面都是要执行函数的参数
//t1.detach();// 与主线程分离
//t2.detach();
t1.join();//主线程等待子线程执行完
system("pause");
return 0;
}
结果

二 线程安全与同步
#include <thread>
int num = 0;
void showNum(string str)
{
while (num < 10)
{
cout << str << "num:" << num << endl;
num++;
}
}
int main()
{
thread t1(showNum, "线程一");
thread t2(showNum, "线程二");
//t1.detach();// 与主线程分离
//t2.detach();
t1.join();//主线程等待子线程执行完
t2.join();
system("pause");
return 0;
}
结果

如图,结果乱七八糟
解决方法
1 互斥锁
#include <thread>
#include <mutex>
mutex mx;
int num = 0;
void showNum(string str)
{
while (num < 10)
{
mx.lock();
cout << str << "num:" << num << endl;
num++;
mx.unlock();
}
}
int main()
{
thread t1(showNum, "线程一");
thread t2(showNum, "线程二");
//t1.detach();// 与主线程分离
//t2.detach();
t1.join();//主线程等待子线程执行完
t2.join();
system("pause");
return 0;
}
结果

结果正确
三种加锁方式
void showNum(string str)
{
while (num < 10)//第一种加锁方式
{
mx.lock();
cout << str << "num:" << num << endl;
num++;
mx.unlock();
}
// while (num < 10)//第二种加锁方式
// {
// lock_guard<mutex> guard(mx);
// cout << str << "num:" << num << endl;
// num++;
//
// }
// while (num < 10) //第三种加锁方式
// {
// unique_lock<mutex> ul(mx);
// cv.wait(ul);
// cout << str << "num:" << num << endl;
// cv.notify_one();
// }
}
这三种方式都是一样的效果 第一种手动加锁,解锁;
第二种和第三种都是再构造里加锁,再析构里解锁;但是第二种参数较少,所以为了更多的控制所以出了第三种方式
2 条件变量
此时我们将加数字与打印分成两个线程
#include <thread>
#include <mutex>
mutex mx;
int num = 0;
condition_variable cv;
void showNum(string str)
{
while (num < 10)
{
unique_lock<mutex> ul(mx);
cv.wait(ul);
cout << str << "num:" << num << endl;
cv.notify_one();
}
}
void numPlus()
{
while (num < 10)
{
unique_lock<mutex> ul(mx);
num++;
cv.notify_one();
cv.wait(ul);
}
}
int main()
{
thread t1(showNum, "线程一");
thread t2(numPlus);
//t1.detach();// 与主线程分离
//t2.detach();
t1.join();//主线程等待子线程执行完
t2.join();
system("pause");
return 0;
}
结果

3 信号量
信号量(semaphore)是一种同步机制,但在C++11中并没有原生提供该机制,那么就需要自己去实现。信号量可以想象成一种跨线程安全的资源的计数,包括两个基本操作:
post,每调用一次post,这种资源就多一个;
wait,每调用一次wait,这种资源便消耗掉一个。如果当前没有这种资源,那么就阻塞等待,直至有其他线程post,该线程才会wakeup。
class Semaphore
{
private:
int count;//资源数量
mutex m;
condition_variable cv;
public:
Semaphore(int count_) : count(count_) {}
// post操作:上锁,资源加1,唤醒一个线程
void post()
{
{
unique_lock<mutex> loc(m);
count++;
}
cv.notify_one();
}
// wait操作:上锁,资源为0,阻塞,否则资源减一
void wait()
{
unique_lock<mutex> loc(m);
if (count == 0)
{
cv.wait(loc);
}
count--;
}
};
使用
class Semaphore
{
private:
int count;//资源数量
mutex m;
condition_variable cv;
public:
Semaphore(int count_) : count(count_) {}
// post操作:上锁,资源加1,唤醒一个线程
void post()
{
{
unique_lock<mutex> loc(m);
count++;
}
cv.notify_one();
}
// wait操作:上锁,资源为0,阻塞,否则资源减一
void wait()
{
unique_lock<mutex> loc(m);
if (count == 0)
{
cv.wait(loc);
}
count--;
}
};
Semaphore s(0);
Semaphore s2(0);
int num = 0;
void showNum(string str)
{
while (num < 10)
{
s.wait();//阻塞
cout << str << "num:" << num << endl;
s2.post();
}
}
void numPlus()
{
while (num < 10)
{
s.post();//唤醒
num++;
s2.wait();
}
}
int main()
{
thread t1(showNum, "线程一");
thread t2(numPlus);
//t1.detach();// 与主线程分离
//t2.detach();
t1.join();//主线程等待子线程执行完
t2.join();
system("pause");
return 0;
}
结果

这里使用了两个信号量来保证有序打印
本文介绍了C++中线程同步的基本概念,并通过实例详细解析了互斥锁、条件变量和信号量等线程同步机制的使用方法。
647





