Mutex and condition variables in POSIX programming

write in front (question)

For a long time before writing this article, almost all the protection of multi-threaded shared data was implemented by adding 互斥量asynchronous primitives sleep, resulting in reduced performance and lower CPU utilization.
Do not use code blocks like this:

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

Later, some problems were found: If the sleep time is too long, the reading and writing data will not be real-time (for example, the mobile phone controls the movement of the robot), if the sleep time is too short, the task kernel will allocate too many time slices, resulting in more CPU usage, which is in vain A lot of performance is wasted (Q:但阻塞或中断性能这块是否也是cpu分时间片轮询呢?).
Thread waiting in production code can be divided into two types, one is waiting for the arrival of resources (such as some multiplexed IO, generally the application state waits for the kernel state to be available, select/poll/eppl_wait, etc.); the other is waiting for the critical section Read and write shared data when available.


Multithreading uses mutex + sleep mode ( 不推荐) to process shared resources

Thread I produces data, and Thread II consumes data.

/*使用该接口替代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);
}

Mutex plus condition variable (c implementation)

Thread I (producer)
pthread_cond_signal(&cond); indicates writing data to the shared area (Boolean value, such as judging the number of caches in the shared area, the Boolean value has changed), triggering a soft interrupt

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

The end of thread II (consumer)
is the wait end, and there is only one correct way to use the condition variable:
1) It must be used together with a mutex, and the read and write of the Boolean expression needs to be protected by this mutex.
2) Wait() can only be called when the mutex is locked;
3) Put the judgment Boolean condition and wait() in the while loop, and you cannot use if to judge.

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);
}

Mutual exclusion plus condition (C++ implementation)

use:

#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;
}










Guess you like

Origin blog.csdn.net/nc_linux/article/details/125003396