线程邮箱
项目中用到了线程邮箱,之后还会更新几篇其他线程同步的文章,应该会包括互斥锁、信号量、条件变量、线程屏障和线程池,有兴趣可以搜一下相互学习。
线程邮箱就是模拟收发邮件的形式,使线程任务不在主动争抢共享资源,只是检查自己的“邮箱”看是否有别的任务对自己有资源的传递。避免了频繁加锁、解锁引起的系统资源消耗。
线程邮箱可以分为三个层次:线程邮箱系统、线程邮箱、邮件。
其中线程邮箱系统mbs
在主线程中起到管理者的作用,系统中的邮箱以链表的形式存储。
//邮箱系统
typedef struct mail_box_system
{
pthread_mutex_t mutex; //保护邮件系统
MAILBOX *thread_list;
}MBS;
线程邮箱MAILBOX
是一个个链表的节点
//邮箱
typedef struct LinkNode{
LIST_DATA elem;
struct LinkNode *next;
}MAILBOX;
邮件是以队列的方式存储在邮箱中的,其中存储着线程tid
,进程名称,进程中队列的队头和队尾和该邮箱对应的函数。
//邮箱中的内容
typedef struct thread_node
{
pthread_t tid; //线程id号
char name[256]; //线程名字 ,必须唯一
Que *mail_head, *mail_tail;
th_fun th;
}LIST_DATA;
邮件是以队列的方式组织在一起,邮件中有发送者的id
和name
以及接收者的id
和name
,还有邮件中最重要的需要传递的数据。
typedef struct mail_data
{
pthread_t id_of_sender;
char name_of_sender[256];
pthread_t id_of_recver;
char name_of_recver[256];
DATATYPE data;
}MAIL_DATA;
typedef struct queue{
MAIL_DATA data;
struct queue* next;
}Que;
使用时需要先创建邮箱系统:
MBS* create_mail_box_system()
{
MBS *temp =(MBS*)malloc(sizeof(MBS));
if(NULL == temp){
perror("create_mail_box_system mutex malloc failure\n");
return NULL;
}
//完成邮箱系统中保护锁的初始化
int ret = pthread_mutex_init(&temp->mutex,NULL);
if(0 != ret){
perror("create_mail_box_system mutex init failure\n");
return NULL;
}
temp->thread_list = malloc(sizeof(MAILBOX));
temp->thread_list->next = NULL;
printf("mail box create ok!! \n");
return temp;
}
注册邮箱,每一个业务都需要有一个邮箱,将邮箱加入到邮箱系统中。
int register_to_mail_system(MBS *mbs,char name[],th_fun th)
{
MAILBOX* temp = malloc(sizeof(MAILBOX));
if(NULL == temp){
perror("register to mail malloc \n");
return -1;
}
strcpy(temp->elem.name ,name); //邮箱的名字
temp->elem.th = th; //邮箱对应的函数
init_que(temp);
list_add(mbs->thread_list, temp); //将邮箱加入系统中的邮箱链表
pthread_t ret = pthread_create(&temp->elem.tid,NULL,th,NULL);
if(0!=ret){
perror("register to mail thread create\n");
return -1;
}
printf("register mail system |%s| ok \n", temp->elem.name);
return 0;
}
接下来是最重要的两个函数,send_msg
以及recv_msg
函数。
int send_msg(MBS*msb, char*recvname, DATATYPE data)
{
MAIL_DATA* temp = malloc(sizeof(MAIL_DATA));
strcpy(temp->data, data);
temp->id_of_sender = pthread_self();
//在系统中要有想要函数发送邮件的邮箱
MAILBOX *find = list_for_each(msb->thread_list, recvname);
if (find == NULL){
printf("can,t find recv mailbox\n");
}
char* name = get_th_name(msb); //通过当前线程的tid获得当前线程的名字
strcpy(temp->name_of_sender,name);
strcpy(temp->name_of_recver,recvname);
ENTER_CRITICAL_AREA(&msb->mutex); //加锁
in_queue(find, temp); //将邮件发送到邮箱
QUIT_CRITICAL_AREA(&msb->mutex); //解锁
return 0;
}
int recv_msg(MBS *msb, char *sendname, DATATYPE data)
{
MAIL_DATA* temp = malloc(sizeof(MAIL_DATA));
pthread_t tid = pthread_self();
//在邮箱系统中找到对应的邮箱
MAILBOX *find = msb->thread_list->next;
while(find != NULL){
if(find->elem.tid == tid)
break;
find = find->next;
}
//如果队列中存在数据,出队
if(find != NULL && find->elem.tid == tid){
while (1){
if(find->elem.mail_head != find->elem.mail_tail){
ENTER_CRITICAL_AREA(&msb->mutex);
out_queue(find, temp);
QUIT_CRITICAL_AREA(&msb->mutex);
break;
}
}
}
//填充data
strcpy(sendname, temp->name_of_sender);
strcpy(data, temp->data);
free(temp); ‣ptr: temp
return 0;
}
测试结果:
注册三个邮箱以及对应的线程函数,data1
线程每隔1s发送111
,data2
线程每隔3s发送1122
,show
线程打印。