POSIX编程之互斥和条件变量

前言


在写这边文章之前很长一段时间,几乎关于多线程对共享数据的保护都是使用互斥量加非同步原语sleep实现,导致性能的降低和cpu的利用率降低。
不要使用如下的代码块:

while(true){
	if(!dataAvailable)
	sleep(some_time);
	else
	consumeData();
}

后来发现一些问题: 如果sleep时间过长,会导致读写数据不实时(比如手机控制机器人运动),如果sleep的时间过短,导致任务内核分的时间片过多,导致CPU占用比较多,白白浪费了大量的性能(Q:但阻塞或中断性能这块是否也是cpu分时间片轮询呢?)。
生产代码中线程的等待可分为两种,一种是等待资源的到来(比如一些复用IO,一般是应用态等待内核态可用,select/poll/eppl_wait等);一种是等着临界区可用时读写共享数据。


多线程对共享资源使用互斥量+sleep方式

  • 是否推荐

线程I生产数据,线程II消费数据。

/*使用该接口替代sleep,原因为sleep的精度不高(涉及到調度延遲),因为设计进程调用等原因
	我們稱爲該接口為優化后的定時器<<UNIX網絡變成卷1>> 6.3 P129
*/
void milliseconds_sleep(int mSec)
{
    struct timeval tv;
    tv.tv_sec=mSec/1000;
    tv.tv_usec=(mSec%1000)*1000;
    int err;
    do{
       err=select(0,NULL,NULL,NULL,&tv);
    }while(err<0 && errno==EINTR);
}
//线程I
while(ture)
{
	pthread_mutex_lock(&mutex);
	//写 共享数据区
	pthread_mutex_unlock(&mutex);
	
	milliseconds_sleep(40);
}
线程II:
while(ture)
{
	pthread_mutex_lock(&mutex);
	//读 共享数据区
	pthread_mutex_unlock(&mutex);
	
	milliseconds_sleep(40);
}

互斥加条件变量(c实现)

线程I(生产者)
pthread_cond_signal(&cond);表示对共享区写数据(布尔值,比如判断共享区缓存的数量,布尔值改变了),触发软中断

while(true == is_run )
{
	pthread_mutex_lock(&lock);
	//对共享区写数据,改变布尔值,改变的时候通常用mutex保护
	do somethings ...
	pthread_mutex_unlock(&lock);
	pthread_cond_signal(&cond);
}

线程II(消费者)
该端为wait端,条件变量只有一种正确使用方式:
1)必须与mutex一起使用,该布尔表达式的读写 需此mutex保护。
2)在mutex已上锁的时候才能调用wait();
3)把判断布尔条件和wait()放到while循环中,不能使用if去判断。

while(true = =is_run)
{
	pthread_mutex_lock(&lock);//满足2)
	while(!ringbuf.size())	//满足3)
	{	
		pthread_cond_wait(&cond, &lock); //满足1)
	}
	if(false == is_run)
	{
		pthread_mutex_unlock(&lock);
		break;
	}
	//读共享区数据,例如链表,队列等
	do somethings...
	pthread_mutex_unlock(&lock);
}

互斥加条件(C++实现)

使用:

#ifndef FUNC_H__
#define FUNC_H__

#include <thread>
#include <vector>
#include "muduo/base/Mutex.h"
#include "muduo/base/Condition.h"

#include "muduo/base/Thread.h"
#include "muduo/base/Types.h"


using namespace muduo;
class CCaptureMgr
{
public:
	typedef struct TagCapture
	{
		char *data;
		size_t	siz;
	}CAPTURE_S;

//	enum {MEMERY_TYPE = 0, FILE_FD_TYPE = 1, CPLUSPLUS_THREAD_TYPE = 2 };
	

	static CCaptureMgr *inst(){static CCaptureMgr cm; return &cm;}

	 int start();
	 int restart();
	 int stop();
	
protected:
	int deleteSource(std::thread *);
	int deleteSource(std::vector<CAPTURE_S> &);

	void pushProc();
	void popProc();

	int put(const CAPTURE_S &);
	int take();

private:
	CCaptureMgr();
	~CCaptureMgr();

	mutable MutexLock mutex_ ;
	Condition cond_ GUARDED_BY(mutex_);
	
	

	std::thread *pPushHandle_;
	std::thread *pPopHandle_;

	bool bRun_;

	std::vector<CAPTURE_S> captureDataList_;
};



#endif


#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "function.hpp"




CCaptureMgr::CCaptureMgr():pPushHandle_(nullptr), pPopHandle_(nullptr),bRun_(true),
			mutex_(), cond_(mutex_)
{}

CCaptureMgr::~CCaptureMgr()
{}


int CCaptureMgr::put(const CAPTURE_S &hs_)
{
	MutexLockGuard lock(mutex_);
	//if(hs_.data && hs_.siz)
	{
		captureDataList_.push_back(hs_);
		cond_.notify();
	}
}

int CCaptureMgr::take()
{
	MutexLockGuard lock(mutex_);
	while(captureDataList_.empty())
	{
		cond_.wait();
	}
	std::cout << "siz: " << captureDataList_.size() << std::endl;
	
}


void CCaptureMgr::pushProc()
{
	while(bRun_)
	{
		static int recore = 0;
		CAPTURE_S capture;
		memset(&capture, 0, sizeof(capture));
		capture.data = (char *)calloc(1, 1024);
		capture.siz = strlen(capture.data);
		put(capture);
		sleep(1);
		
		
	}
}

void CCaptureMgr::popProc()
{
	while(bRun_)
	{
		take();
		
	}
}

int CCaptureMgr::start()
{
	int ret = 0;


	if(nullptr == pPopHandle_)
	{
		pPopHandle_ = new std::thread(&CCaptureMgr::popProc, this);
		if(!pPopHandle_)
		{
			std::cout << "创建POP线程失败! " << std::endl;
		}
	}

	if(nullptr == pPushHandle_)
	{
		pPushHandle_ = new std::thread(&CCaptureMgr::pushProc, this);
		if(!pPushHandle_)
		{
			std::cout << "创建PUSH线程失败! " << std::endl;
		}
	}

	return 0;
}

int CCaptureMgr::restart()
{
	stop();
	start();
}

int CCaptureMgr::deleteSource(std::thread *p)
{
	if(p)
	{
		p->join(); delete p; p = 0;
	}
}
int CCaptureMgr::deleteSource(std::vector<CAPTURE_S> &hs_)
{
	if(hs_.size())
	{
		auto it = hs_.begin();
		for(it; it != hs_.end(); ++it)
		{
			if(it->data)
			{
				free(it->data); it->data = 0;
			}
		}
	}
}
int CCaptureMgr::stop()
{
	deleteSource(pPushHandle_);
	deleteSource(pPopHandle_);

	return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值