Linux线程邮箱

线程邮箱

项目中用到了线程邮箱,之后还会更新几篇其他线程同步的文章,应该会包括互斥锁、信号量、条件变量、线程屏障和线程池,有兴趣可以搜一下相互学习。
线程邮箱就是模拟收发邮件的形式,使线程任务不在主动争抢共享资源,只是检查自己的“邮箱”看是否有别的任务对自己有资源的传递。避免了频繁加锁、解锁引起的系统资源消耗。

线程邮箱可以分为三个层次:线程邮箱系统、线程邮箱、邮件。
其中线程邮箱系统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;

邮件是以队列的方式组织在一起,邮件中有发送者的idname以及接收者的idname,还有邮件中最重要的需要传递的数据。

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发送111data2线程每隔3s发送1122show线程打印。

  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线程邮箱是一种线程间通信的机制,它允许一个线程向另一个线程发送消息。在C语言中,可以使用信号量和队列来实现线程邮箱。 下面是一个使用信号量实现线程邮箱的示例代码: ```c #include <stdio.h> #include <pthread.h> #include <semaphore.h> #define MAX_MESSAGES 100 #define MAX_MESSAGE_LENGTH 50 char messages[MAX_MESSAGES][MAX_MESSAGE_LENGTH]; int message_count = 0; int message_index = 0; sem_t message_mutex; sem_t message_count_sem; sem_t message_space_sem; void add_message(char *message) { sem_wait(&message_space_sem); sem_wait(&message_mutex); snprintf(messages[message_index], MAX_MESSAGE_LENGTH, "%s", message); message_index = (message_index + 1) % MAX_MESSAGES; message_count++; sem_post(&message_mutex); sem_post(&message_count_sem); } void *producer(void *arg) { char buffer[MAX_MESSAGE_LENGTH]; while (1) { printf("Enter a message: "); fgets(buffer, MAX_MESSAGE_LENGTH, stdin); add_message(buffer); } } void remove_message(char *message) { sem_wait(&message_count_sem); sem_wait(&message_mutex); snprintf(message, MAX_MESSAGE_LENGTH, "%s", messages[message_index]); message_index = (message_index + 1) % MAX_MESSAGES; message_count--; sem_post(&message_mutex); sem_post(&message_space_sem); } void *consumer(void *arg) { char buffer[MAX_MESSAGE_LENGTH]; while (1) { remove_message(buffer); printf("Received message: %s", buffer); } } int main() { pthread_t producer_thread, consumer_thread; sem_init(&message_mutex, 0, 1); sem_init(&message_count_sem, 0, 0); sem_init(&message_space_sem, 0, MAX_MESSAGES); pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); sem_destroy(&message_mutex); sem_destroy(&message_count_sem); sem_destroy(&message_space_sem); return 0; } ``` 在这个示例中,我们使用了三个信号量来实现线程邮箱: - `message_mutex` 用于保护消息队列的互斥访问。 - `message_count_sem` 用于表示消息队列中当前的消息数量。 - `message_space_sem` 用于表示消息队列中还有多少空间可以添加新的消息。 `add_message` 函数将消息添加到消息队列中,首先获取 `message_space_sem` 和 `message_mutex` 的锁,然后将消息添加到队列中,更新消息数量并释放锁。 `remove_message` 函数从消息队列中移除消息,首先获取 `message_count_sem` 和 `message_mutex` 的锁,然后从队列中获取消息,更新消息数量并释放锁。 `producer` 函数用于向消息队列中添加消息,它从标准输入中读取消息并调用 `add_message` 函数添加到队列中。 `consumer` 函数用于从消息队列中获取消息,它调用 `remove_message` 函数从队列中移除消息并打印出来。 在 `main` 函数中,我们初始化了三个信号量并创建了一个生产者线程和一个消费者线程。然后等待这两个线程退出并销毁信号量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值