最近在工作中遇到了问题一个纠结问题:一个底层通用的模块,在应用层有许多线程使用。该模块大多数情况下都是正常的,模块出问题之后或基于其他考虑需要重启底层模块,底层重启了之后理论上是应用层需要释放当前资源,重新开始应用层业务。
为了实现该目标,当前以使用方式是:底层模块重启前调用每一个应用程接口,通知他们释放当前资源。但感觉这个设计有些缺陷:完全破坏了底层模块的封装完整性。
然后首先想到的是应用层,自己不停的检测底层模块的状态,但是觉得有点不太麻烦,需要一个while(1){check},有点低效
最后想到了tcp 中的组播思想,首先将需要监控底层模块的线程加入一个分组内,当底层模块状态需要发生改变时,给组内每个线程发送一个通知消息。应用线程接收到通知消息之后,释放当前资源,重新开始业务。
下面是这个线程组播的消息的源代码,源码仅仅是一个demo,用于阐述线程组播思想的框架,在实际引用中需要用户自己完善。
#include <signal.h>
#include <pthread.h>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5
typedef struct{
pthread_t pid_th;
void (*sig_pro)(int);
}board_sig;
board_sig siglist[MAX];
void th1_sighandler(int signo)
{
pthread_t tid = pthread_self();
printf("thread with pid:%lu receive signo:%d, I am th1 pro\n", tid, signo);
return;
}
void th2_sighandler(int signo)
{
pthread_t tid = pthread_self();
printf("thread with pid:%lu receive signo:%d, I am th2 pro\n", tid, signo);
return;
}
void th3_sighandler(int signo)
{
pthread_t tid = pthread_self();
printf("thread with pid:%lu receive signo:%d, I am th3 pro\n", tid, signo);
return;
}
void sighandler(int signo)
{
pthread_t tid = pthread_self();
int i = 0;
for(i = 0; i < MAX; i++)
{
if(tid == siglist[i].pid_th)
{
siglist[i].sig_pro(signo);
}
}
}
void Init_User1Sig_Board(pthread_t pid_th, void (*sig_pro)(int))
{
int i = 0;
for(i = 0; i < MAX; i++)
{
if(siglist[i].pid_th == 0)
{
siglist[i].pid_th = pid_th;
siglist[i].sig_pro = sig_pro;
break;
}
}
}
User1Sig_Board_Pro()
{
int i = 0;
for(i = 0; i < MAX; i++)
{
if(siglist[i].pid_th != 0)
{
printf("i = %d, pid_th = %lu\n", i, siglist[i].pid_th);
pthread_kill(siglist[i].pid_th,SIGUSR1);
//usleep(1000);
}
}
}
void * thr1_fn(void *arg)
{
pthread_t tid = pthread_self();
printf("thread 1 with tid:%lu\n", tid);
Init_User1Sig_Board(tid, th1_sighandler);
sleep(15);
return NULL;
}
void *thr2_fn(void *arg)
{
pthread_t tid = pthread_self();
printf("thread 2 with tid:%lu\n", tid);
Init_User1Sig_Board(tid, th2_sighandler);
sleep(15);
return NULL;
}
void *thr3_fn(void *arg)
{
pthread_t tid = pthread_self();
printf("thread 3 with tid:%lu\n", tid);
Init_User1Sig_Board(tid, th3_sighandler);
sleep(15);
return NULL;
}
int main(void)
{
int rc, err;
pthread_t thr1, thr2, thr3, thrm = pthread_self();
struct sigaction action;
action.sa_flags = 0;
action.sa_handler = sighandler;
sigaction(SIGUSR1, &action, NULL);
printf("thread main with pid %lu\n",thrm);
err = pthread_create(&thr1, NULL, thr1_fn, NULL);
if (err != 0) {
printf("error in creating pthread:%d\t%s\n",err, strerror(rc));
exit(1);
}
/* pthread_kill(thr1, SIGALRM); send a SIGARLM signal to thr1 before thr2 set the signal handler, then the whole process will be terminated*/
err = pthread_create(&thr2, NULL, thr2_fn, NULL);
if (err != 0) {
printf("error in creating pthread:%d\t%s\n",err, strerror(rc));
exit(1);
}
err = pthread_create(&thr3, NULL, thr3_fn, NULL);
if (err != 0) {
printf("error in creating pthread:%d\t%s\n",err, strerror(rc));
exit(1);
}
sleep(10);
//内部产生的信号,只有指定的线程能收到,因此要向所有线程发送
User1Sig_Board_Pro();
pthread_join(thr1, NULL); /*wait for the threads to complete.*/
pthread_join(thr2, NULL);
pthread_join(thr3, NULL);
printf("main ends\n");
return 0;
}
编译调试结果:
# gcc c.c -o c -lpthread
# ./c
thread main with pid 3075667648
thread 3 with tid:3058879296
thread 2 with tid:3067272000
thread 1 with tid:3075664704
i = 0, pid_th = 3058879296
i = 1, pid_th = 3067272000
i = 2, pid_th = 3075664704
thread with pid:3058879296 receive signo:10, I am th3 pro
thread with pid:3067272000 receive signo:10, I am th2 pro
thread with pid:3075664704 receive signo:10, I am th1 pro
main ends