C++高级编程----多线程编程

题目要求:1)假设有一个Counter类,包含一个id和计数次数mNumIters,支持多线程(互斥体)完成计数任务;2)设计一个发送者和消费者模式的数据传输模型;3)支持多线程加法运算,实现每个Counter自加后结果不变;4)考虑设计一个日志类,多线程读写数据,写入数据后存储到log.txt文件中。

分析:
1)定义基于mutex的多线程任务,mutex支持lock_gurad和unique_lock等加锁方式,考虑重写类Counter的operator(),实现参数传递;
2)定义基于条件变量的多线程任务,condition_variable支持wait()和notify_all()/notify_one()等方法根据条件完成对已加锁的mutex的操作;
3)定义原子性counter,每个线程完成各自的加法运算值递增到counter中,保持数据同步;
4)Logger类需要考虑数据存储结构,此处定义为队列queue<string>,通过互斥体保护队列数据的访问,考虑到可能存在后台程序崩溃,需要设计相应的析构函数和对应的是否退出的原子性变量mExit
5) 标准库多线程的编译指令:g++ -Wall -pthread -g -o desApp source.cpp

代码实现:
1:互斥体的基本方法

/*************************************************************************
   > File Name: mutexDemo.cpp
   > Author: xxx
   > Mail: email@xx.com 
   > Created Time: 2021年12月08日 星期三 15时51分30秒
************************************************************************/

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<climits>

#include<mutex>
#include<chrono>
#include<thread>

using namespace std;

class Counter{
   public:
   	Counter(int id, int numIters):mId(id), mNumIters(numIters){
   	}
   	// lock_guard
   	/*
   	void operator()() const{
   		for(int i = 0; i < mNumIters; ++i){
   			lock_guard<mutex> lock(mMutex);
   			cout << "Counter " << mId << " has value " << i << endl;
   		}
   	}*/
   	// unique_lock
   	void operator()() const{

   		for(int i = 0; i < mNumIters; ++i){
   			unique_lock<timed_mutex> lock(mTimeMutex, 200ms);
   			if(lock){
   				cout <<"Counter " << mId << " has value " << i << endl;
   			}
   			// else lock 200ms
   		}
   	}

   private:
   	int mId;
   	int mNumIters;
   	// static mutex mMutex for lock_guard;
   	static timed_mutex mTimeMutex;
};

// mutex Counter::mMutex;
timed_mutex Counter::mTimeMutex;

int main(){
   thread t1{Counter{1, 30}};
   Counter c(2, 15);
   thread t2(c);
   thread t3(Counter(3, 10));
   t1.join();
   t2.join();
   t3.join();
   return 0;
}

2、条件变量的使用方法(使用条件变量和互斥体的区别)

/*************************************************************************
    > File Name: condVarDemo.cpp
    > Author: xxx
    > Mail: email@xx.com 
    > Created Time: 2021年12月08日 星期三 16时14分09秒
 ************************************************************************/

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<climits>

#include<thread>
#include<mutex>
#include<deque>
#include<chrono>
#include<condition_variable>

using namespace std;

std::deque<int> q; // global queue
std::mutex mMutex; // global mutex
std::condition_variable mCondVar; //global condition variable

void provider(){
	int count = 10;
	while(count > 0){
		unique_lock<mutex> lock(mMutex);
		q.push_front(count);
		lock.unlock();
		std::this_thread::sleep_for(std::chrono::seconds(1));
		count--;
	}
}

void consumer(){
	int data = 0;
	while(data != 1){
		unique_lock<mutex> lock(mMutex);
		if(!q.empty()){
			data = q.back();
			q.pop_back();
			lock.unlock();
			cout << "consumter get data from provider: " << data << endl;
		}else{
			lock.unlock();
			std::this_thread::sleep_for(std::chrono::milliseconds(500));
		}
	}
}

void providerII(){
	int count = 10;
	while(count > 0){
		unique_lock<mutex> lock(mMutex);
		q.push_front(count);
		lock.unlock();
		// add condvar notification
		mCondVar.notify_one();
		std::this_thread::sleep_for(std::chrono::seconds(1));
		count--;
	}
}

void consumerII(){
	int data = 0;
	while(data != 1){
		unique_lock<mutex> lock(mMutex);
		/*while(q.empty()){	// note for multitime to check queue data
			mCondVar.wait(lock);
		} for better understand, use next line to replace*/
		mCondVar.wait(lock, [](){return !q.empty();});
		data = q.back();
		q.pop_back();
		lock.unlock();
		cout << "consumer get data from provider: " << data << endl;
	}
}

int main(){
	thread t1(providerII);
	thread t2(consumerII);
	t1.join();
	t2.join();
    return 0;
}

3:原子操作(线程中函数的传入是复制形式传入,转换为引用传入需要使用std::ref(var))

/*************************************************************************
    > File Name: atomicDemo.cpp
    > Author: xxx
    > Mail: email@xx.com 
    > Created Time: 2021年12月08日 星期三 14时40分34秒
 ************************************************************************/

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<climits>

#include<thread>
#include<atomic>
#include<chrono>

using namespace std;

void func(int& counter){
	for(int i = 0; i < 100; ++i){
		++counter;
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
}

void funcII(std::atomic<int>& counter){
	int res = 0; // to improve performence
	for(int i = 0; i < 100; ++i){
		++res;
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	counter += res;
}

int main(){
	// int counter = 0;
	std::atomic<int> counter(0);
	std::vector<std::thread> threads;
	for(int i = 0; i < 10; ++i){

		threads.push_back(std::thread{funcII, std::ref(counter)});
	}
	for(auto& t : threads){
		t.join();
	}
	cout << "Result = " << counter << endl;
    return 0;
}

4:Logger类实现方法

//logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#include<queue>
#include<thread>
#include<string>
#include<mutex>
#include<condition_variable>
#include<atomic>

class Logger{
    public:
        Logger();
        Logger(const Logger& src) = delete;
        Logger& operator=(const Logger& rhs) = delete;
        void log(const std::string& entry);
        virtual ~Logger();
    private:
        std::atomic<bool> mExit;
        // Mutex and condition variable to protect access to the queue
        std::mutex mMutex;
        std::condition_variable mCondVar;
        std::queue<std::string> mQueue;
        std::thread mThread;
        void processEntries();
};
#endif

//logger.cpp
#include<fstream>
#include<iostream>
#include"logger.h"
using namespace std;
Logger::Logger(): mExit(false){
    mThread = thread{&Logger::processEntries, this};
}
Logger::~Logger(){
    {
        unique_lock<mutex> lock(mMutex);
        mExit = true;
        mCondVar.notify_all();
    }
    mThread.join();
}
void Logger::log(const std::string& entry){
    unique_lock<mutex> lock(mMutex);
    mQueue.push(entry);
    mCondVar.notify_all();
}
void Logger::processEntries(){
    ofstream ofs("log.txt");
    if(ofs.fail()){
        cout << "Fail to open logfile. " << endl;
    }
    unique_lock<mutex> lock(mMutex);
    while(true){
        if(!mExit){
            mCondVar.wait(lock);
        }
        lock.unlock();
        while(true){
            lock.lock();
            if(mQueue.empty()){
                break;
            }else{
                ofs << mQueue.front() << endl;
                mQueue.pop();
            }
            lock.unlock();
        }
        if(mExit){
            break;
        }
    }
}

// main.cpp
#include<iostream>
#include<sstream>
#include<thread>
#include<vector>
#include"logger.h"
using namespace std;
void logSomeMessages(int id, Logger& logger){
    for(int i = 0; i < 10; i++){
        stringstream ss;
        ss << "Log entry " << i << " from thread " << id;
        logger.log(ss.str());
    }
}

int main(){
    Logger logger;
    vector<thread> threads;
    for(int i = 0; i < 10; i++){
        threads.emplace_back(logSomeMessages, i, ref(logger));
    }
    for(auto& t : threads){
        t.join();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值