基于C语言的线程通信消息队列实现

         在多线程编程中经常需要进行线程与线程间的通信,由于线程间能够共享数据结构,也就是一个全局变量能够被两个线程同时候使用。但是要注意的是线程的同步互斥
         线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
         线程互斥是指当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。一般采用互斥锁来解决互斥的问题,但是使用时一定要注意避免死锁。

         在接收回调数据的时候,不能进行太过耗时的处理,通常将数据拷贝至消息队列,在其他线程进行处理。如下为项目总结的消息队列和使用示例:

msg_process.c

#include 
#include 
#include 
#include "msg_process.h"


#define LOG_ERR(fmt, ...) do{\
	printf("[ERROR]  "fmt"  [line:%d] [%s]\n", ##__VA_ARGS__, __LINE__, __FUNCTION__);\
}while(0);

static unsigned long timeout_ns = 0;

/**
 * 消息处理模块内部接口
 */
static void put_msg_to_buffer(tmsg_buffer* buf, tmsg_element* elm){
	if (NULL == buf || NULL == elm) {
		return;
	}

	if (NULL != elm->next) {
		elm->next = NULL;
	}

	pthread_mutex_lock(&buf->mutex);
	//缓冲区中无消息节点
	if (0 == buf->num) {
		gettimeofday(&timenow,NULL);
		timeout.tv_sec = timenow.tv_sec + block/1000; //加上秒数
		block %= 1000;	//得到毫秒数

		timeout_ns = timenow.tv_usec*1000 + block*1000*1000;
		if( timeout_ns >= 1000*1000*1000 ) //若超过1s
		{
			timeout.tv_sec ++;
			timeout.tv_nsec = timeout_ns - 1000*1000*1000;
		}
		else
			timeout.tv_nsec = timeout_ns;
		//带超时时间阻塞线程等待消息节点
		pthread_cond_timedwait(&buf->not_empty, &buf->mutex, &timeout);
	}

	pthread_mutex_unlock(&buf->mutex);
}


static tmsg_element* get_msg_from_buffer(tmsg_buffer* buf, int block){
	tmsg_element *elm = NULL;

	if (NULL == buf) {
		return NULL;
	}

	pthread_mutex_lock(&buf->mutex);
	//缓冲区中无消息节点
	while (0 == buf->num) {
		//阻塞线程等待消息节点
		pthread_cond_wait(&buf->not_empty, &buf->mutex);
	}
	//从缓冲区首部取出消息节点
	elm = buf->first;
	if (1 == buf->num) {
		buf->first = buf->last = NULL;
		buf->num = 0;
	} else {
		buf->first = buf->first->next;
		buf->num --;
	}

	pthread_mutex_unlock(&buf->mutex);

	return elm;
}



static tmsg_element* get_msg_from_buffer_timeout(tmsg_buffer* buf, int block/*ms*/){
	tmsg_element *elm = NULL;
	struct timeval timenow;
	struct timespec timeout;

	if (NULL == buf) {
		return NULL;
	}

	pthread_mutex_lock(&buf->mutex);
	//缓冲区中无消息节点
	if (0 == buf->num) {
		gettimeofday(&timenow);
		timeout.tv_sec = timenow.tv_sec;
		timeout.tv_nsec = (timenow.tv_usec + block * 1000) * 1000;
		//带超时时间阻塞线程等待消息节点
		pthread_cond_timedwait(&buf->not_empty, &buf->mutex, &timeout);
	}

	if (buf->num > 0) {
		//从缓冲区首部取出消息节点
		elm = buf->first;
		if (1 == buf->num) {
			buf->first = buf->last = NULL;
			buf->num = 0;
		} else {
			buf->first = buf->first->next;
			buf->num --;
		}
	}

	pthread_mutex_unlock(&buf->mutex);

	return elm;
}


static tmsg_element* clear_msg_buffer(tmsg_buffer* buf){
	tmsg_element* elm = NULL;
	tmsg_element* elm_tmp = NULL;

	if (NULL == buf){
		return NULL;
	}

	//清空buffer中当前消息节点之前的所有消息节点
	pthread_mutex_lock(&buf->mutex);
	if (buf->num > 0) {
		elm = buf->first;
		while(elm != NULL) {
			//首尾指针指向同一消息节点
			if (elm == buf->last) {
				buf->first = buf->last;
				if (buf->num != 1) {
					buf->num = 1;
				}
				break;
			}

			elm_tmp = elm->next;
			free_tmsg_element(elm);
			buf->num --;
			elm = elm_tmp;
			buf->first = elm;
		}
	}

	pthread_mutex_unlock(&buf->mutex);

	return elm;
}


static void send_msg_to_buffer(tmsg_buffer* buf, int msg, int ext, char* str, int len)
{
	tmsg_element *elm = NULL;

	elm = (tmsg_element *)malloc(sizeof(tmsg_element));
	if (NULL == elm) {
		LOG_ERR("new msg element failed!!");
		return;
	}

	//填充消息节点数据
	memset(elm, 0, sizeof(tmsg_element));
	elm->msg = msg;
	elm->ext = ext;
	elm->dt = NULL;
	elm->dt_len = len;
	if (str) 
	{
		elm->dt = (char *)malloc(len);  //根据发送的大小申请内存
		memmove(elm->dt, str, len);
	}
	
	elm->next = NULL;
	//将消息节点添加到缓冲区中
	put_msg_to_buffer(buf, elm);
}


static void send_msg_to_buffer_ex(tmsg_buffer* buf, int msg, int ext, int sub0, int sub1, char* str, int len){
	tmsg_element *elm = NULL;

	elm = (tmsg_element *)malloc(sizeof(tmsg_element));
	if (NULL == elm) {
		LOG_ERR("new msg element failed!!");
		return;
	}

	//填充消息节点数据
	memset(elm, 0, sizeof(tmsg_element));
	elm->msg = msg;
	elm->ext = ext;
	elm->sub0 = sub0;
	elm->sub1 = sub1;
	elm->dt = NULL;
	elm->dt_len = len;
	if (str) 
	{
		elm->dt = (char *)malloc(len);  //根据发送的大小申请内存
		memmove(elm->dt, str, len);
	}
	elm->next = NULL;
	//将消息节点添加到缓冲区中
	put_msg_to_buffer(buf, elm);
}


static void dispose_msg_buffer(tmsg_buffer* buf){
	tmsg_element* elm = NULL;

	if (NULL == buf) {
		return;
	}

	if (buf->first != buf->last
			&& buf->num > 0) {
		elm = clear_msg_buffer(buf);
	} else {
		elm = buf->last;
	}

	if (NULL != elm) {
		free_tmsg_element(elm);
		buf->first = buf->last = NULL;
		buf->num = 0;
	}

	pthread_mutex_destroy(&buf->mutex);
	pthread_cond_destroy(&buf->not_empty);
	free(buf);

	buf = NULL;
}


static int get_msg_num(tmsg_buffer* buf){
	if (NULL == buf) {
		return 0;
	}

	return buf->num;
}


/**
 * 以下为消息处理模块对外接口
 */

/*消息缓冲区初始化*/
tmsg_buffer* msg_buffer_init(void){
	tmsg_buffer* msg_buffer = NULL;

	msg_buffer = (tmsg_buffer *)malloc(sizeof(tmsg_buffer));
	if (NULL == msg_buffer){
		LOG_ERR("init msg buffer failed!!");
		return NULL;
	}

	//初始化成员变量和函数
	memset(msg_buffer, 0, sizeof(tmsg_buffer));
	msg_buffer->first = NULL;
	msg_buffer->last = NULL;
	msg_buffer->num = 0;

	pthread_mutex_init(&(msg_buffer->mutex), NULL);
	pthread_cond_init(&(msg_buffer->not_empty), NULL);

	//继续绑定接口
	msg_buffer->put = put_msg_to_buffer;
	msg_buffer->get = get_msg_from_buffer;
	msg_buffer->get_timeout = get_msg_from_buffer_timeout;
	msg_buffer->clear = clear_msg_buffer;
	msg_buffer->sendmsg = send_msg_to_buffer;
	msg_buffer->sendmsgex = send_msg_to_buffer_ex;
	msg_buffer->dispose = dispose_msg_buffer;
	msg_buffer->getnum = get_msg_num;

	return msg_buffer;
}


/*复制消息节点*/
tmsg_element* dup_msg_element(tmsg_element* elm){
	tmsg_element* msg_element = NULL;
	if (NULL == elm) {
		LOG_ERR("msg element is NULL!!");
		return NULL;
	}

	msg_element = (tmsg_element *)malloc(sizeof(tmsg_element));
	if (NULL == msg_element) {
		LOG_ERR("create msg element is failed!!");
		return NULL;
	}

	memcpy(msg_element, elm, sizeof(tmsg_element));

	return msg_element;
}

void free_tmsg_element(tmsg_element *msg_element)
{
	if(msg_element != NULL)
	{
        if(msg_element->dt != NULL)
	    {
		    free(msg_element->dt);
		    msg_element->dt = NULL;
	    }
		free(msg_element);
		msg_element = NULL;
	}
}

msg_process.h

#ifndef _MSG_PROCESS_H_
#define _MSG_PROCESS_H_
#include 

typedef struct msg_element tmsg_element;

struct msg_element
{
    tmsg_element* next;
    int msg;
    int ext;
    int sub0;
    int sub1;
    int dt_len;
    char *dt;
};


typedef struct msg_buffer tmsg_buffer;

struct msg_buffer
{
    tmsg_element* first;
    tmsg_element* last;
    int             num;

    pthread_mutex_t mutex;
    pthread_cond_t  not_empty;

    void (*put)(tmsg_buffer* buf, tmsg_element* elm);
    tmsg_element* (*get)(tmsg_buffer* buf, int block);
    tmsg_element* (*get_timeout)(tmsg_buffer* buf, int block);

    tmsg_element* (*clear)(tmsg_buffer* buf);
    void (*sendmsg)(tmsg_buffer* buf, int msg, int ext, char* str, int len);
    void (*sendmsgex)(tmsg_buffer* buf, int msg, int ext, int sub0, int sub1, char* str, int len);
    void (*dispose)(tmsg_buffer* buf);

    int (*getnum)(tmsg_buffer* buf) ;
};



/*消息缓冲区初始化*/
tmsg_buffer* msg_buffer_init(void);


/*复制消息节点*/
tmsg_element* dup_msg_element(tmsg_element* elm);

/*释放消息节点*/
void free_tmsg_element(tmsg_element *msg_element);


#endif /* MESSAGE_MSG_CENTER_H_ */

example.c  //调用示例

#include
#include "msg_process.h"

int main(int argc,char *argv[])
{

	tmsg_buffer* test_msg_buff = NULL;
	test_msg_buff = msg_buffer_init();
	char table[] = "{\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\","
				   "\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\""
				   ",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\""
				   ",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\""
				   ",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\",\"hello\",\"world\"}";
	test_msg_buff->sendmsg(test_msg_buff,0,0,table,sizeof(table)); //发送数据

	sleep(2);

	tmsg_element* event = NULL;
	event = test_msg_buff->get_timeout(test_msg_buff,1000);  //接收数据
	if(event != NULL)
	{
		if(event->dt != NULL)
		{
			int i = 0;
			printf("Recv:");
			for(i=0; idt_len; i++)
			{
				printf("%c",event->dt[i]);
			}
			printf("\n");
		}
	}
	free_tmsg_element(event);
	
    return 0;
}

执行结果

基于C语言的线程通信消息队列实现_第1张图片

你可能感兴趣的:(C语言学习,Linux基础学习)