一、如果单纯的启动多个进程,那么代码如下:
//总体思路:父进程创建多个子进程,并且使用一个特殊标记值,使每个子进程这个数值都不同
//父进程创建子进程之后,根据这个特殊数值依次给进程分配要执行的代码
for(i = 0;i < thread_num;i++)
{
if(0 == (thread_pid[i] = topo_fork()))
{
//每个子进程thread_mark都有一个唯一的数值,该值依次递增,从1开始。
thread_mark = i + 1;
break;
}
else
{
printf("thread(%d): %d\n",i,thread_pid[i]);
}
}
//根据thread_mark数值不同,设置条件,使不同的进程执行不同的代码。
//父进程的thread_mark为0
if(0 == thread_mark)
{
printf("This is parent process start\n");
//父进程执行的代码
parent_main_loop();
}
//第一个子进程的thread_mark为1
else(thread_mark == 1)
{
printf("This is snmp child process start\n");
//第一个进程执行的代码
topo_main_loop();
}
//第二个子进程的thread_mark为2
else(thread_mark == 2)
{
printf("This is watchdog child process start\n");
//第二个进程执行的代码
watchdog_main_loop();
}
这样做的缺点是要启动的进程个数是确定的,哪个功能要启动几个进程也是确定的,而zabbix里面启动多少个进程是不确定的,哪个功能要启动多少个进程也是不确定的,比如poller进程的个数,是可以配置文件配置个数的。
二、zabbix多进程实现
int CONFIG_ALERTER_FORKS = 1;
int CONFIG_DISCOVERER_FORKS = 1;
int CONFIG_HOUSEKEEPER_FORKS = 1;
int CONFIG_NODEWATCHER_FORKS = 1;
int CONFIG_PINGER_FORKS = 1;
int CONFIG_POLLER_FORKS = 5;
int CONFIG_UNREACHABLE_POLLER_FORKS = 1;
int CONFIG_HTTPPOLLER_FORKS = 1;
int CONFIG_IPMIPOLLER_FORKS = 0;
int CONFIG_TIMER_FORKS = 1;
int CONFIG_TRAPPER_FORKS = 5;
int CONFIG_SNMPTRAPPER_FORKS = 0;
int CONFIG_JAVAPOLLER_FORKS = 0;
int CONFIG_ESCALATOR_FORKS = 1;
int CONFIG_SELFMON_FORKS = 1;
int CONFIG_WATCHDOG_FORKS = 1;
int CONFIG_DATASENDER_FORKS = 0;
int CONFIG_HEARTBEAT_FORKS = 0;
int CONFIG_CONFSYNCER_FORKS = 1;
int MAIN_ZABBIX_ENTRY()
{
pid_t pid;
int i, server_num = 0, server_count = 0;
//要启动的进程数量由这些变量的值决定,配置值为1就启动该进程,为0就不启动该进程。
//这些值有的有默认值,有的根据配置文件决定。
threads_num = CONFIG_CONFSYNCER_FORKS + CONFIG_WATCHDOG_FORKS + CONFIG_POLLER_FORKS
+ CONFIG_UNREACHABLE_POLLER_FORKS + CONFIG_TRAPPER_FORKS + CONFIG_PINGER_FORKS
+ CONFIG_ALERTER_FORKS + CONFIG_HOUSEKEEPER_FORKS + CONFIG_TIMER_FORKS
+ CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS
+ CONFIG_HISTSYNCER_FORKS + CONFIG_ESCALATOR_FORKS + CONFIG_IPMIPOLLER_FORKS
+ CONFIG_JAVAPOLLER_FORKS + CONFIG_SNMPTRAPPER_FORKS + CONFIG_PROXYPOLLER_FORKS
+ CONFIG_SELFMON_FORKS;
threads = zbx_calloc(threads, threads_num, sizeof(pid_t));
//使用fork()产生新的进程,thread_num是多少,就产生多少个进程。
//fork()产生新进程的过程中,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零
//所以此处使用if,else结构,会使父进程和子进程执行不同的代码
for (i = 0; i < threads_num; i++)
{
if (0 == (pid = zbx_child_fork()))
{
//每个子进程都中的server_num都会有一个唯一的依次递增的值
//根据server_num这个在每个进程中数值都不一样的特点,可以在下面实现每个子进程去执行不同的代码
//子进程执行break,直接跳出循环,去执行进程之后的代码
server_num = i + 1; /* child processes are numbered starting from 1 */
break;
}
else
//父进程返回的是子进程的进程号,父进程将每个子进程的进程号记录在thread[]结构中
threads[i] = pid;
}
//父进程的server_num为0,每个子进程都有不同的server_num,根据server_num的不同,使不同的进程执行不同的代码。
if (0 == server_num)
{
zabbix_log(LOG_LEVEL_INFORMATION, "server #0 started [main process]");
while (-1 == wait(&i)) /* wait for any child to exit */
{
if (EINTR != errno)
{
zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));
break;
}
}
/* all exiting child processes should be caught by signal handlers */
THIS_SHOULD_NEVER_HAPPEN;
zbx_on_exit();
}
//server_count是已启动的子进程的个数,CONFIG_CONFSYNCER_FORKS为本次要启动的子进程的个数,server_num为每个子进程的标记值,
//以server_num <= (server_count += CONFIG_CONFSYNCER_FORKS)为条件,可实现让子进程依次去执行相关的代码功能
//server_count初始值为0,第一个子进程的server_num数值为1,
//如果CONFIG_CONFSYNCER_FORKS为0,则server_count += CONFIG_CONFSYNCER_FORKS 数值为0,不满足1<=0,不执行main_dbconfig_loop()
//如果CONFIG_CONFSYNCER_FORKS为1,则server_count += CONFIG_CONFSYNCER_FORKS 数值为1,满足1 <= 1,把main_dbconfig_loop()作为子进程要执行的代码。
//如果CONFIG_CONFSYNCER_FORKS为2,则server_count += CONFIG_CONFSYNCER_FORKS 数值为2,第一个子进程执行时满足1<=2,执行main_dbconfig_loop()
//第二个子进程执行时,满足2<=2,执行main_dbconfig_loop();由此可以实现同样的功能启动多个进程。CONFIG_CONFSYNCER_FORKS就是该功能启动进程的个数。
else if (server_num <= (server_count += CONFIG_CONFSYNCER_FORKS))
{
INIT_SERVER(ZBX_PROCESS_TYPE_CONFSYNCER, CONFIG_CONFSYNCER_FORKS);
main_dbconfig_loop();
}
else if (server_num <= (server_count += CONFIG_WATCHDOG_FORKS))
{
INIT_SERVER(ZBX_PROCESS_TYPE_WATCHDOG, CONFIG_WATCHDOG_FORKS);
main_watchdog_loop();
}
return SUCCEED;
}
进程要有描述,这样才知道是哪个进程在执行哪个功能。有利于程序调试。
//对进程的描述,记录哪个进程执行的是什么功能
//get_process_type_string根据传入的参数,执行switch case结构,返回对进程的描述。传入的参数为程序中宏定义的变量
//server_num为第几个进程,et_process_type_string(process_type)为对进程执行功能的描述,process_num为该功能启动进程的计数(因为有的功能要启动多个进程)
#define INIT_SERVER(type, count) \
process_type = type; \
process_num = server_num - server_count + count; \
zabbix_log(LOG_LEVEL_INFORMATION, "server #%d started [%s #%d]", \
server_num, get_process_type_string(process_type), process_num)
#define ZBX_PROCESS_TYPE_POLLER 0
#define ZBX_PROCESS_TYPE_UNREACHABLE 1
#define ZBX_PROCESS_TYPE_IPMIPOLLER 2
#define ZBX_PROCESS_TYPE_PINGER 3
#define ZBX_PROCESS_TYPE_JAVAPOLLER 4
#define ZBX_PROCESS_TYPE_HTTPPOLLER 5
#define ZBX_PROCESS_TYPE_TRAPPER 6
#define ZBX_PROCESS_TYPE_SNMPTRAPPER 7
#define ZBX_PROCESS_TYPE_PROXYPOLLER 8
#define ZBX_PROCESS_TYPE_ESCALATOR 9
#define ZBX_PROCESS_TYPE_HISTSYNCER 10
#define ZBX_PROCESS_TYPE_DISCOVERER 11
#define ZBX_PROCESS_TYPE_ALERTER 12
#define ZBX_PROCESS_TYPE_TIMER 13
#define ZBX_PROCESS_TYPE_NODEWATCHER 14
#define ZBX_PROCESS_TYPE_HOUSEKEEPER 15
#define ZBX_PROCESS_TYPE_WATCHDOG 16
#define ZBX_PROCESS_TYPE_DATASENDER 17
#define ZBX_PROCESS_TYPE_CONFSYNCER 18
#define ZBX_PROCESS_TYPE_HEARTBEAT 19
#define ZBX_PROCESS_TYPE_SELFMON 20
#define ZBX_PROCESS_TYPE_COUNT 21 /* number of process types */
#define ZBX_PROCESS_TYPE_UNKNOWN 255
const char *get_process_type_string(unsigned char process_type)
{
switch (process_type)
{
case ZBX_PROCESS_TYPE_POLLER:
return "poller";
case ZBX_PROCESS_TYPE_UNREACHABLE:
return "unreachable poller";
case ZBX_PROCESS_TYPE_IPMIPOLLER:
return "ipmi poller";
case ZBX_PROCESS_TYPE_PINGER:
return "icmp pinger";
case ZBX_PROCESS_TYPE_JAVAPOLLER:
return "java poller";
case ZBX_PROCESS_TYPE_HTTPPOLLER:
return "http poller";
case ZBX_PROCESS_TYPE_TRAPPER:
return "trapper";
case ZBX_PROCESS_TYPE_SNMPTRAPPER:
return "snmp trapper";
case ZBX_PROCESS_TYPE_PROXYPOLLER:
return "proxy poller";
case ZBX_PROCESS_TYPE_ESCALATOR:
return "escalator";
case ZBX_PROCESS_TYPE_HISTSYNCER:
return "history syncer";
case ZBX_PROCESS_TYPE_DISCOVERER:
return "discoverer";
case ZBX_PROCESS_TYPE_ALERTER:
return "alerter";
case ZBX_PROCESS_TYPE_TIMER:
return "timer";
case ZBX_PROCESS_TYPE_NODEWATCHER:
return "node watcher";
case ZBX_PROCESS_TYPE_HOUSEKEEPER:
return "housekeeper";
case ZBX_PROCESS_TYPE_WATCHDOG:
return "db watchdog";
case ZBX_PROCESS_TYPE_DATASENDER:
return "data sender";
case ZBX_PROCESS_TYPE_CONFSYNCER:
return "configuration syncer";
case ZBX_PROCESS_TYPE_HEARTBEAT:
return "heartbeat sender";
case ZBX_PROCESS_TYPE_SELFMON:
return "self-monitoring";
}
assert(0);
}