通过对公司项目的一段时间的研究,对其编写逻辑有一些自己的理解
首先项目分为几个大模块,每个大模块的书写逻辑很类似,这里对单个抽象大模块进行分析:
模块结构:
每个大模块有一个主函数,主函数的作用是定义全局变量,定义一些功能函数,这些函数主函数不去实现它,而是将函数外包给模块内线程模块去实现,线程模块内的一些原子函数,会外包给上一层原子模块去实现也就是说每个大模块有 主函数->线程函数->原子函数
这样递进实现功能
主模块获取原子模块函数,线程模块获取原子模块函数,这个由Makefile文件控制,Makefile文件编译主模块,预处理头文件的时候会根据Makefile内的地址寻找到具体函数位置
下面用一个缩小工程实例描述上述过程:
主模块:
main.h
#ifndef __MAIN_H__
#define __MAIN_H__
extern int main_to_function_flag; // main.h定义全局变量让function.c文件操作
extern int main_to_zkw_flag; // main.h定义全局变量让zkw.c文件操作
void* main_to_function_thread(void* arg); // main.h定义函数让function.c文件实现
void* main_to_zkw_thread(void* arg); // main.h定义函数让zkw.c文件实现
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
#include <pthread.h>
#include <unistd.h>
/*
* 主进程,调用线程模块实现函数
*/
int main_to_function_flag = 100;
int main_to_zkw_flag = 1000; // 声明全局变量
pthread_t function_thread;
pthread_t zkw_thread; // 定义线程id
int main(int argc, char *argv[]) {
if(pthread_create(&function_thread, NULL, main_to_function_thread, NULL) != 0){
printf("function thread创建失败\n");
return -1;
}
if(pthread_create(&zkw_thread, NULL, main_to_zkw_thread, NULL) != 0){
printf("zkw thread创建失败\n");
}
while(1);
}
线程模块:
function.c
#include <stdio.h>
#include "main.h"
/*
* function线程模块,实现项目中的function线程功能
*/
void* main_to_function_thread(void* arg){
while(1) zkw_to_atom1_achieve(&main_to_function_flag); // 调用atom1中原子函数
return NULL;
}
zkw.c
#include <stdio.h>
#include "main.h"
#include "atom1.h"
#include "atom2.h"
/*
* zkw线程模块实现zkw线程功能
*/
void* main_to_zkw_thread(void* arg){
while(1) zkw_to_atom2_achieve(&main_to_zkw_flag); // 调用atom2中原子函数
return NULL;
}
原子模块:
atom1.h
#ifndef __ATOM1_H__
#define __ATOM1_H__
void zkw_to_atom1_achieve(int* num);
#endif
atom1.c
#include <stdio.h>
#include <unistd.h>
/*
* 原子模块1,实现原子功能
*/
void zkw_to_atom1_achieve(int* num){
(*num) ++;
printf("这里是原子1,输出为: %d\n", *num);
sleep(1);
}
atom2.h
#ifndef __ATOM2_H__
#define __ATOM2_H__
void zkw_to_atom2_achieve(int* num);
#endif
atom1.c
#include <stdio.h>
#include <unistd.h>
/*
* 原子模块2,实现原子功能
*/
void zkw_to_atom2_achieve(int* num){
(*num) += 5;
printf("这里是原子2,输出为:%d\n", *num);
sleep(5);
}
上述过程:
主模块用于声明并定义全局变量,声明线程函数,在主进程中开两个线程分别运行线程函数,主进程循环等待。
线程模块用于实现线程函数在线程函数中调用到原子函数。
原子模块用于声明并实现原子函数
补充:
调用头文件的时候,可以理解为调用这个文件内的接口函数,每个接口函数最多被实现一次,否者会报错,调用接口函数会根据头文件寻找到实现函数的链接接找到函数的实现。