文章目录
- 一、关于多线程的同步
- 二、初始条件变量
- 三、关于条件变量的例题
- 四、生产者消费者模型
一、关于多线程的同步
//函数被调用,分配相应的栈帧,进行现场保护
void func(char c)
{
char filename[20] = {};
sprintf(filename, "test%c.txt",c);
FILE *fp=fopen(filename, "w");
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 10; ++j)
{
fprintf(fp,"%c ",c);
}
fprintf(fp,"\n");
}
fprintf(fp,"\n");
}
int main()
{
thread tha(func, 'A');
thread thb(func, 'B');
thread thc(func, 'C');
thread thd(func, 'D');
thread the(func, 'E');
tha.join();
thb.join();
thc.join();
thd.join();
the.join();
}
打印结果,每个文件里面分别打印出ABCDE
二、初始条件变量
关于条件变量的API函数
std::mutex m_cv;
std::condition_variable cv;
std::string mydata;
bool ready = false;
bool processed = false;
void worker_thread()
{
std::unique_lock<std::mutex>lock(m_cv); //构造函数,获得锁,块作用域结束后,调用析构函数,释放锁
while (!ready)
{
cv.wait(lock); //1.解锁 2.放在条件变量等待队列中 3.唤醒条件变量,放入互斥锁等待队列中 4.互斥锁到就绪状态,再次获得锁
}
mydata+= "处理数据完成";
cout << mydata << endl;
processed = true;
//lock.unlock();
cv.notify_one();
}
int main()
{
std::thread tha(worker_thread);
mydata += "data"; //块作用域
{
std::unique_lock<std::mutex>lock(m_cv);
ready = true;
cout << "main() signale data ready for processing" << endl;
}
cv.notify_one();
{
std::unique_lock<std::mutex>lock(m_cv);
while (!processed)
{
cv.wait(lock);
}
}
cout << "back int main() , data" << endl;
tha.join();
return 0;
}
在这个程序里面两个主线程和子线程同时运行,看谁先获得锁,如果子线程先获得锁,则进入wait状态,在wait状态里面有四个步骤
- 释放锁
- 将数据放入条件变量等待对列中
- 唤醒条件变量,加入到互斥锁队列
- 互斥锁到就绪状态,再次获得锁
当wait状态执行到第二步时候,此时主线程获得锁,主线程向下执行,将tag的值变为true,此时再次到子线程,此时子线程向下执行,wait执行三、四步骤后,再次调用唤醒函数,主线程执行后续步骤
三、关于条件变量的例题
例题一:ABC三个线程分别打印出来ABC
const int n = 10;
int tag = 1;
std::mutex mtx;
std::condition_variable cv;
void funa()
{
std::unique_lock<std::mutex>lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 1)
{
cv.wait(lock);
}
printf("funa :%c\n", 'A');
tag = 2;
cv.notify_one();
}
}
void funb()
{
std::unique_lock<std::mutex>lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 2)
{
cv.wait(lock);
}
printf("funb :%c\n", 'B');
tag = 3;
cv.notify_one();
}
}
void func()
{
std::unique_lock<std::mutex>lock(mtx);
for (int i = 0; i < n; ++i)
{
while (tag != 3)
{
cv.wait(lock);
}
printf("func :%c\n", 'C');
tag = 1;
cv.notify_one();
}
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
std::thread thc(func);
tha.join();
thb.join();
thc.join();
}
运行结果:
例题二:ABC三个线程分别打印出100之内所有数
const int n = 100;
int i = 0;
std::mutex mtx;
std::condition_variable cv;
void funa()
{
std::unique_lock<std::mutex>lock(mtx);
while (i <= n)
{
while (i%3!=0&&i<=n)
{
cv.wait(lock);
}
if (i > 100)return;
printf("funa:%d\n", i);
i += 1;
cv.notify_all();
}
}
void funb()
{
std::unique_lock<std::mutex>lock(mtx);
while (i <= n)
{
while (i%3!= 1&&i<=n)
{
cv.wait(lock);
}
if (i > 100)return;
printf("funb:%d\n", i);
i += 1;
cv.notify_all();
}
}
void func()
{
std::unique_lock<std::mutex>lock(mtx);
while (i <= n)
{
while (i%3 != 2&&i<=n)
{
cv.wait(lock);
}
if (i > 100)return;
printf("func:%d\n", i);
i += 1;
cv.notify_all();
}
}
int main()
{
thread tha(funa);
thread thb(funb);
thread thc(func);
tha.join();
thb.join();
thc.join();
}
例题三:A线程打印偶数,B线程打印奇数
const int n = 100;
int i = 0;
bool tag = true; //false 奇数
std::mutex mtx;
std::condition_variable cv;
void funa()
{
std::unique_lock<std::mutex>lock(mtx);
for (; i <=n; )
{
/*while (i % 2 != 0 && i <= n)
{
cv.wait(lock);
}*/
cv.wait(lock, [&]()->bool {return !(i % 2 != 0 && i <= n); }); //先判断lamanda表达式是否为真,如果为真,则直接退出
if (i <=n)
{
printf("funa: %d\n", i);
}
i += 1;
cv.notify_one();
}
}
void funb()
{
std::unique_lock<std::mutex>lock(mtx);
for (; i <= n; )
{
while (i % 2 == 0 && i <= n)
{
cv.wait(lock);
}
if (i <= n)
{
printf("funb: %d\n", i);
}
i += 1;
cv.notify_one();
}
}
int main()
{
thread tha(funa);
thread thb(funb);
tha.join();
thb.join();
}
四、生产者消费者模型
//生产者消费者模型
const int n = 100;
int i = 0;
int mydata;
bool ready = false;
std::mutex mtx;
bool stop = true; //拓展,消费者不管生产者生产了多少数据,消费者始终进行消费
std::condition_variable cv;
void Produce()
{
std::unique_lock<std::mutex>lock(mtx);
for (int i=0; i <=n;++i)
{
while (ready)
{
cv.wait(lock);
}
mydata = i;
printf("生产者生产数据:%d\n", mydata);
ready = true;
cv.notify_all();
}
stop = false;
printf("生产者结束\n");
}
void Consumer1()
{
std::unique_lock<std::mutex>lock(mtx);
while(stop)
{
while (!ready)
{
cv.wait(lock);
}
printf("消费者一消费数据:%d\n", mydata);
ready = false;
cv.notify_all();
}
}
void Consumer2()
{
std::unique_lock<std::mutex>lock(mtx);
while (stop)
{
while (!ready)
{
cv.wait(lock);
}
printf("消费者二消费数据:%d\n", mydata);
ready = false;
cv.notify_all();
}
}
int main()
{
thread tha(Produce);
thread thb(Consumer1);
thread thc(Consumer2);
tha.join();
thb.join();
thc.join();
return 0;
}
使用队列解决生产者消费者模型
//队列实现生产者和消费者
const int n = 100;
class MyQueue
{
private:
std::deque<int>qu;
std::mutex m_cv;
std::condition_variable cv;
std::size_t MaxElem = 8;
public:
MyQueue(){}
~MyQueue(){}
MyQueue(const MyQueue&) = delete; //C++11新特性
MyQueue& operator=(const MyQueue&) = delete;
void put(int val)
{
std::unique_lock<std::mutex>lock(m_cv);
while (qu.size() >= MaxElem)
{
cv.wait(lock);
}
qu.push_back(val);
printf("Produce data:%d\n", val);
cv.notify_one(); //唤醒
}
int get()
{
std::unique_lock<std::mutex>lock(m_cv);
while (qu.empty())
{
cv.wait(lock);
}
int val = qu.front();
qu.pop_front();
cv.notify_all();
return val;
}
};
void Produre(MyQueue& qu)
{
for (int i = 1; i <= n; ++i)
{
qu.put(i);
}
}
void Consumer(MyQueue& qu)
{
for (int i = 1; i <= n; ++i)
{
int x = qu.get();
cout << "Consumer: " << x << endl;
}
}
int main()
{
MyQueue mqu;
std:: thread tha(Produre,std::ref(mqu));
std::thread thb(Consumer,std::ref(mqu));
tha.join();
thb.join();
}
出现死锁的情况
//死锁,解决死锁的方式,同时获取锁,同时释放锁
std::mutex mx1;
std::mutex mx2;
void funa()
{
cout << "funa begin..." << endl;
std::unique_lock<std::mutex>lock1(mx1);
cout << "funa 拿到mx1" << endl;
cout << "wait 拿到mx2" << endl;
std::unique_lock<std::mutex>lock2(mx2);
cout << "funa end..." << endl;
}
void funb()
{
cout << "funb begin..." << endl;
std::unique_lock<std::mutex>lock2(mx2);
cout << "funb 拿到mx2" << endl;
cout << "wait 拿到mx1" << endl;
std::unique_lock<std::mutex>lock1(mx1);
cout << "funb end..." << endl;
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
tha.join();
thb.join();
}
运行结果:
原因分析:并不是一运行就会出现这种情况,当出现图片中的这种情况的时候,原因是当两个互斥锁同时运行时,锁一被占用后,还没有释放锁的时候,锁二就继续占用锁一,出现了相互引用的情况,导致了死锁的出现。
解决死锁的办法
重写此程序:
std::mutex mx1;
std::mutex mx2;
void funa()
{
cout << "funa begin..." << endl;
std::unique_lock<std::mutex>lock1(mx1,std::defer_lock); //不获得互斥锁的所有权
std::unique_lock<std::mutex>lock2(mx2, std::defer_lock);
std::lock(lock1, lock2); //将锁同时锁住,在将锁同时释放
cout << "funa 拿到mx1" << endl;
cout << "wait 拿到mx2" << endl;
cout << "funa end..." << endl;
}
void funb()
{
cout << "funb begin..." << endl;
std::unique_lock<std::mutex>lock2(mx2, std::defer_lock);
std::unique_lock<std::mutex>lock1(mx1, std::defer_lock);
std::lock(lock2, lock1);
cout << "funb 拿到mx2" << endl;
cout << "wait 拿到mx1" << endl;
cout << "funb end..." << endl;
}
int main()
{
std::thread tha(funa);
std::thread thb(funb);
tha.join();
thb.
关于银行转账死锁的问题
甲向乙进行转账的同时,乙向甲进行转账
#include <mutex>
#include <iostream>
#include <thread>
#include <condition_variable>
#include <set>
#include <unordered_set>
using namespace std;
mutex mx;
condition_variable cv;
class Count
{
public:
Count(int m) : money(m) {}
~Count() = default;
bool operator<(const Count& src)const { return money < src.money; }
int getMoney() { return money; }
void setMoney(int m) { money = m; }
private:
int money;
};
class Account
{
private:
Account() = default;
Account(const Account & src) = delete;
Account& operator=(const Account & src) = delete;
set<Count*> s;
public:
~Account() = default;
static Account* getInstance()
{
static Account a;
return &a;
}
void apply(Count& A, Count& B)
{
unique_lock<mutex> lc(mx); //申请账户 先上锁
while (s.count(&A) > 0 || s.count(&B) > 0)
{
cv.wait(lc); //阻塞等待
}
s.insert(&A);
s.insert(&B);
}
void free(Count& A, Count& B)
{
unique_lock<mutex> lc(mx);
s.erase(&A);
s.erase(&B);
cv.notify_all();
}
};
void thread_func1(Count& A, Count& B, int money) //A---> B转账money元
{
Account* acc = Account::getInstance();
acc->apply(A, B);
if (A.getMoney() >= money)
{
A.setMoney(A.getMoney() - money);
B.setMoney(B.getMoney() + money);
cout << "successful:" << endl;
cout << money << endl;
}
else
{
cout << "余额不足" << endl;
}
acc->free(A, B);
}
int main()
{
Count A(1000);
Count B(1000);
thread s1(thread_func1, ref(A), ref(B), 300); //A----->B 300
thread s2(thread_func1, ref(B), ref(A), 100); //B----->A 100
s1.join();
s2.join();
cout << A.getMoney() << endl;
cout << B.getMoney() << endl;
system("pause");
return 0;
}
用户态到内核态怎么切换
http://t.csdn.cn/H7PAH
两个线程怎么切换
http://t.csdn.cn/O0oFb
死锁产生的原因和解决办法
http://t.csdn.cn/1AK4y