├── .gitignore ├── assets ├── logo │ ├── logo_28.png │ ├── logo_1000.png │ ├── logo_128.png │ ├── logo_512.png │ └── logo_512.svg └── logic_block_diagram.png ├── .clang-format ├── inc ├── z_table_print.h ├── z_kfifo.h ├── z_thpool.h ├── z_tool.h └── z_debug.h ├── Makefile ├── src ├── z_tool.c ├── z_table_print.c ├── test.c ├── z_kfifo.c └── z_thpool.c ├── README.zh-CN.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.o 3 | *.a 4 | .compile_commands.json 5 | .cache 6 | z_thpool_test 7 | -------------------------------------------------------------------------------- /assets/logo/logo_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitStreamlet/z_thpool/HEAD/assets/logo/logo_28.png -------------------------------------------------------------------------------- /assets/logo/logo_1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitStreamlet/z_thpool/HEAD/assets/logo/logo_1000.png -------------------------------------------------------------------------------- /assets/logo/logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitStreamlet/z_thpool/HEAD/assets/logo/logo_128.png -------------------------------------------------------------------------------- /assets/logo/logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitStreamlet/z_thpool/HEAD/assets/logo/logo_512.png -------------------------------------------------------------------------------- /assets/logic_block_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BitStreamlet/z_thpool/HEAD/assets/logic_block_diagram.png -------------------------------------------------------------------------------- /assets/logo/logo_512.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | SortIncludes: false 2 | BasedOnStyle: Google 3 | PointerAlignment: Right 4 | AccessModifierOffset: -4 5 | IndentWidth: 4 6 | MaxEmptyLinesToKeep: 1 7 | BreakBeforeBraces: Attach 8 | AllowShortFunctionsOnASingleLine: true 9 | AllowShortIfStatementsOnASingleLine: true 10 | AlignAfterOpenBracket: true 11 | IndentCaseLabels: true 12 | ObjCBlockIndentWidth: 4 13 | ObjCSpaceAfterProperty: true 14 | ColumnLimit: 180 15 | AlignTrailingComments: true 16 | SpaceAfterCStyleCast: false 17 | AlignOperands: true 18 | SpacesInSquareBrackets: false 19 | AlignConsecutiveDeclarations: false 20 | SpacesInContainerLiterals: false 21 | BreakConstructorInitializersBeforeComma: true 22 | AllowAllParametersOfDeclarationOnNextLine: true 23 | ContinuationIndentWidth: 4 24 | TabWidth: 4 25 | SpaceBeforeAssignmentOperators: true 26 | SpacesBeforeTrailingComments: 1 -------------------------------------------------------------------------------- /inc/z_table_print.h: -------------------------------------------------------------------------------- 1 | #ifndef _Z_TABLE_PRINT_H_ 2 | #define _Z_TABLE_PRINT_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | /* Function declarations for table printing utilities */ 9 | 10 | /* Prints the border for a table */ 11 | void z_table_print_border(void); 12 | 13 | /* 14 | * Prints a title within the table. 15 | * @param title: A string representing the title to be printed. 16 | */ 17 | void z_table_print_title(const char *title); 18 | 19 | /* 20 | * Prints a formatted row in the table. 21 | * @param format: A string specifying the format. 22 | * Other parameters are handled as per the format specifications. 23 | */ 24 | void z_table_print_row(const char *format, ...); 25 | 26 | /* 27 | * Sets the width of the table for consistent formatting. 28 | * @param width: An integer representing the desired table width. 29 | */ 30 | void z_table_print_set_width(int width); 31 | 32 | /* 33 | * Defines a custom print function to be used. 34 | * @param print: A pointer to a function that matches the specified signature. 35 | */ 36 | void z_table_print_set_func(void (*print)(const char *format, ...)); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif /* __cplusplus */ 41 | 42 | #endif /* _Z_TABLE_PRINT_H_ */ 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compiler and archiver 2 | CC = gcc 3 | AR = ar 4 | 5 | # Directories 6 | INCDIR = inc 7 | SRCDIR = src 8 | OBJDIR = obj 9 | LIBDIR = lib 10 | BUILD = build 11 | TESTDIR = test 12 | 13 | # Files 14 | LIB = $(LIBDIR)/libz_thpool.a 15 | TEST_LIB = $(LIBDIR)/libtestlib.a 16 | TEST_PROGRAM = $(BUILD)/z_thpool_test 17 | 18 | # Compiler and linker flags 19 | CFLAGS = -std=c99 -I$(INCDIR) -D_DEFAULT_SOURCE 20 | LDFLAGS = -L$(LIBDIR) -lz_thpool -ltestlib -lpthread 21 | 22 | # List all source files 23 | SRC = $(wildcard $(SRCDIR)/*.c) 24 | TEST_SRC = $(wildcard $(TESTDIR)/*.c) 25 | 26 | # Generate object files in obj directory 27 | OBJ = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRC)) 28 | TEST_OBJ = $(patsubst $(TESTDIR)/%.c, $(OBJDIR)/%.o, $(TEST_SRC)) 29 | 30 | # Default target 31 | all: $(LIB) $(TEST_LIB) $(TEST_PROGRAM) 32 | 33 | # Rule to create the library 34 | $(LIB): $(OBJ) 35 | @mkdir -p $(BUILD) 36 | @mkdir -p $(LIBDIR) 37 | $(AR) rcs $@ $^ 38 | 39 | # Rule to create the test library 40 | $(TEST_LIB): $(TEST_OBJ) 41 | @mkdir -p $(LIBDIR) 42 | $(AR) rcs $@ $^ 43 | 44 | # Rule to compile source files into objects 45 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 46 | @mkdir -p $(OBJDIR) 47 | $(CC) $(CFLAGS) -c $< -o $@ 48 | 49 | # Rule to compile test source files into objects 50 | $(OBJDIR)/%.o: $(TESTDIR)/%.c 51 | @mkdir -p $(OBJDIR) 52 | $(CC) $(CFLAGS) -c $< -o $@ 53 | 54 | # Rule to create the main program 55 | $(TEST_PROGRAM): $(OBJ) $(TEST_OBJ) 56 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 57 | 58 | # Clean up all generated files 59 | clean: 60 | rm -rf $(OBJDIR) $(LIBDIR) $(TEST_PROGRAM) 61 | 62 | .PHONY: all clean 63 | -------------------------------------------------------------------------------- /inc/z_kfifo.h: -------------------------------------------------------------------------------- 1 | #ifndef _Z_KFIFO_H_ 2 | #define _Z_KFIFO_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | /* Structure defining a kernel FIFO (First In, First Out) queue */ 9 | struct z_kfifo_struct { 10 | uint8_t *p_buffer; /* Pointer to the buffer holding the data */ 11 | uint32_t size; /* Total size of the allocated buffer */ 12 | uint32_t in; /* Offset where data is added (in % size) */ 13 | uint32_t out; /* Offset where data is extracted (out % size) */ 14 | }; 15 | 16 | /* Initialize the FIFO with an existing buffer and its size */ 17 | void z_kfifo_init(struct z_kfifo_struct *p_fifo, void *p_buffer, uint32_t size); 18 | 19 | /* Allocate a buffer for the FIFO dynamically */ 20 | int z_kfifo_malloc(struct z_kfifo_struct *p_fifo, uint32_t size); 21 | 22 | /* Free the dynamically allocated buffer in the FIFO */ 23 | void z_kfifo_free(struct z_kfifo_struct *p_fifo); 24 | 25 | /* Add data from a source buffer to the FIFO */ 26 | uint32_t z_kfifo_in(struct z_kfifo_struct *p_fifo, const void *p_from, uint32_t len); 27 | 28 | /* Extract data from the FIFO into a destination buffer */ 29 | uint32_t z_kfifo_out(struct z_kfifo_struct *p_fifo, void *p_to, uint32_t len); 30 | 31 | /* Calculate available space for new data in the FIFO */ 32 | uint32_t z_kfifo_space(struct z_kfifo_struct *p_fifo); 33 | 34 | /* Determine the length of the data currently stored in the FIFO */ 35 | uint32_t z_kfifo_data_len(struct z_kfifo_struct *p_fifo); 36 | 37 | /* Check and potentially extract data without removing it from the FIFO */ 38 | uint32_t z_kfifo_out_check(struct z_kfifo_struct *p_fifo, void *p_to, uint32_t len); 39 | 40 | /* Test functionality of the FIFO; could be used for diagnostics or unit testing */ 41 | uint32_t z_kfifo_test(void); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif /* __cplusplus */ 46 | 47 | #endif /* _Z_KFIFO_H_ */ 48 | -------------------------------------------------------------------------------- /inc/z_thpool.h: -------------------------------------------------------------------------------- 1 | #ifndef _Z_THPOOL_H_ 2 | #define _Z_THPOOL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | // Handle type for thread pool instance 9 | typedef struct z_thpool_mng_struct* z_thpool_handle_t; 10 | 11 | // Data structure for configuring the thread pool 12 | struct z_thpool_config_struct { 13 | uint32_t max_thread_nums; // Maximum number of threads in the pool 14 | uint32_t msg_node_max; // Maximum number of message nodes in the pool 15 | uint32_t thread_stack_size; // Stack size for each thread 16 | char pool_name[32]; // Name of the thread pool 17 | }; 18 | 19 | // Function to create a new thread pool instance 20 | // @param p_config: Pointer to a configuration structure specifying pool parameters 21 | // @param p_handle: Pointer to store the created thread pool handle 22 | // @return: Returns 0 on success, or a negative error code on failure 23 | int32_t z_thpool_create(struct z_thpool_config_struct *p_config, z_thpool_handle_t *p_handle); 24 | 25 | // Function to destroy a thread pool instance 26 | // @param handle: Handle to the thread pool to destroy 27 | // @return: Returns 0 on success, or a negative error code on failure 28 | int32_t z_thpool_destroy(z_thpool_handle_t handle); 29 | 30 | // Function to add a work task to the thread pool 31 | // @param handle: Handle to the thread pool 32 | // @param cb: The callback function that defines the task 33 | // @param arg: The argument to pass to the task 34 | // @return: Returns 0 on success, or a negative error code on failure 35 | int32_t z_thpool_add_work(z_thpool_handle_t handle, void (*cb)(void *), void *arg); 36 | 37 | // Function to get thread pool status 38 | // @param handle: Handle to the thread pool 39 | // @return: Returns 0 on success, or a negative error code on failure 40 | int32_t z_thpool_cmd_shell_show(z_thpool_handle_t handle); 41 | 42 | // Function to test the thread pool functionality 43 | // @return: Returns 0 on success, or a negative error code on failure 44 | int32_t z_thpool_test(void); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif /* __cplusplus */ 49 | 50 | #endif /* _Z_CONFIG_H_ */ 51 | -------------------------------------------------------------------------------- /src/z_tool.c: -------------------------------------------------------------------------------- 1 | #include "z_tool.h" 2 | #include "z_debug.h" 3 | #include "z_kfifo.h" 4 | 5 | 6 | struct z_tool_malloc_struct { 7 | unsigned int malloc_count; 8 | unsigned int realloc_count; 9 | unsigned int calloc_count; 10 | unsigned int strdup_count; 11 | unsigned int free_count; 12 | }; 13 | 14 | static struct z_tool_malloc_struct gs_tool_malloc_struct = {0}; 15 | 16 | void *_z_tool_malloc(unsigned int size, const char *file, const char *function, unsigned int line, void *addr){ 17 | void *p = NULL; 18 | p = malloc(size); 19 | if (p == NULL) { 20 | Z_ERROR("malloc failed"); 21 | return NULL; 22 | } 23 | gs_tool_malloc_struct.malloc_count++; 24 | return p; 25 | } 26 | 27 | void *_z_tool_realloc(void *old_ptr, unsigned int size, const char *file, const char *function, unsigned int line, void *addr){ 28 | void *p = NULL; 29 | p = realloc(old_ptr, size); 30 | if (p == NULL) { 31 | Z_ERROR("realloc failed"); 32 | return NULL; 33 | } 34 | gs_tool_malloc_struct.realloc_count++; 35 | return p; 36 | } 37 | 38 | void _z_tool_free(void *ptr, const char *file, const char *function, unsigned int line){ 39 | free(ptr); 40 | gs_tool_malloc_struct.free_count++; 41 | } 42 | 43 | void *_z_tool_calloc(unsigned int num, unsigned int size, const char *file, const char *function, unsigned int line, void *addr){ 44 | void *p = NULL; 45 | p = calloc(num, size); 46 | if (p == NULL) { 47 | Z_ERROR("calloc failed"); 48 | return NULL; 49 | } 50 | gs_tool_malloc_struct.calloc_count++; 51 | return p; 52 | } 53 | 54 | void *_z_tool_strdup(const char *s, const char *file, const char *function, unsigned int line, void *addr){ 55 | void *p = NULL; 56 | p = strdup(s); 57 | if (p == NULL) { 58 | Z_ERROR("strdup failed"); 59 | return NULL; 60 | } 61 | gs_tool_malloc_struct.strdup_count++; 62 | return p; 63 | } 64 | 65 | void z_tool_malloc_info(void){ 66 | Z_INFO("malloc_count: %d", gs_tool_malloc_struct.malloc_count); 67 | Z_INFO("realloc_count: %d", gs_tool_malloc_struct.realloc_count); 68 | Z_INFO("calloc_count: %d", gs_tool_malloc_struct.calloc_count); 69 | Z_INFO("strdup_count: %d", gs_tool_malloc_struct.strdup_count); 70 | Z_INFO("free_count: %d", gs_tool_malloc_struct.free_count); 71 | } -------------------------------------------------------------------------------- /src/z_table_print.c: -------------------------------------------------------------------------------- 1 | #include "z_tool.h" 2 | 3 | // Structure to configure the print table options 4 | struct z_table_print_struct { 5 | int width; // Width of the table, influencing the line length 6 | char buffer[256]; // Buffer to hold printed line content temporarily 7 | void (*print)(const char *format, ...); // Function pointer for custom print functionality 8 | }; 9 | 10 | // Default print function declaration 11 | extern void __z_table_print_default(const char *format, ...); 12 | 13 | // Global instance with default settings for table printing 14 | struct z_table_print_struct gs_table_print = {80, {0}, __z_table_print_default}; 15 | 16 | // Default implementation of the print function 17 | void __z_table_print_default(const char *format, ...) { 18 | va_list args; 19 | va_start(args, format); 20 | vprintf(format, args); 21 | va_end(args); 22 | } 23 | 24 | // Function to print a border line using the specified printer settings 25 | static void __z_table_print_border(struct z_table_print_struct *printer) { 26 | if (printer->print != NULL) { // Check if a print function is set 27 | memset(printer->buffer, '-', printer->width); // Fill buffer with dashes 28 | printer->buffer[printer->width] = '\0'; // Null-terminate the string 29 | printer->print("%s\r\n", printer->buffer); // Printer the border line 30 | } 31 | return; 32 | } 33 | 34 | // Function to print a title within borders using the specified printer settings 35 | static void __z_table_print_title(struct z_table_print_struct *printer, const char *title) { 36 | if (printer->print != NULL) { // Check if a print function is set 37 | __z_table_print_border(printer); // Print top border 38 | snprintf(printer->buffer, printer->width - 4, "| %-*s |", printer->width - 4, title); // Format title row 39 | printer->print("%s\r\n", printer->buffer); // Print the title row 40 | __z_table_print_border(printer); // Print bottom border 41 | } 42 | return; 43 | } 44 | 45 | // Public function to print a table border 46 | void z_table_print_border(void) { 47 | __z_table_print_border(&gs_table_print); 48 | return; 49 | } 50 | 51 | // Public function to print a table title 52 | void z_table_print_title(const char *title) { 53 | __z_table_print_title(&gs_table_print, title); 54 | return; 55 | } 56 | 57 | // Public function to print a formatted row within the table 58 | void z_table_print_row(const char *format, ...) { 59 | struct z_table_print_struct *printer = &gs_table_print; 60 | if (printer->print != NULL) { // Check if a print function is set 61 | va_list args; 62 | va_start(args, format); 63 | vsnprintf(printer->buffer, sizeof(printer->buffer), format, args); // Format row content 64 | va_end(args); 65 | printer->print("%s", printer->buffer); // Print the row content 66 | } 67 | return; 68 | } 69 | 70 | // Public function to set the table's width, ensuring it does not exceed buffer size 71 | void z_table_print_set_width(int width) { 72 | gs_table_print.width = width; 73 | 74 | // Ensure the width does not exceed the buffer's capacity 75 | if (width >= sizeof(gs_table_print.buffer)) { 76 | gs_table_print.width = sizeof(gs_table_print.buffer) - 1; 77 | } 78 | return; 79 | } 80 | 81 | // Public function to set a custom print function 82 | void z_table_print_set_func(void (*print)(const char *format, ...)) { 83 | if (print) { // Verify the function pointer is valid 84 | gs_table_print.print = print; 85 | } 86 | return; 87 | } 88 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | #include "z_tool.h" 2 | #include "z_debug.h" 3 | #include "z_thpool.h" 4 | 5 | #define MAX_POOLS 10 6 | 7 | // Help text for command-line interface 8 | static const char *gs_help = 9 | "\r\n" 10 | "Enter a command (type 'exit' to quit):\r\n\r\n" 11 | "create pool1 5 100 64 #Create pool named 'pool1' with 5 threads, 100 cache queues, 64k stack size\r\n" 12 | "destroy pool1 #Destroy pool named 'pool1'\r\n" 13 | "add pool1 10 #Add 10 tasks to pool named 'pool1'\r\n" 14 | "show pool1 #Show state of pool named 'pool1'\r\n" 15 | "test #Run test suite\r\n" 16 | "help #Show this help\r\n"; 17 | 18 | // Structure to track thread pools 19 | struct pool_entry { 20 | char name[32]; 21 | z_thpool_handle_t handle; 22 | int in_use; 23 | }; 24 | 25 | // Array of thread pools 26 | static struct pool_entry gs_pools[MAX_POOLS] = {0}; 27 | 28 | // Simulate a task by sleeping for 1 second 29 | static void test_task_cb(void *p_arg) { 30 | sleep(1); // Simulating task processing time 31 | } 32 | 33 | // Find a pool by name 34 | static struct pool_entry *find_pool(const char *name) { 35 | for (int i = 0; i < MAX_POOLS; i++) { 36 | if (gs_pools[i].in_use && strcmp(gs_pools[i].name, name) == 0) { 37 | return &gs_pools[i]; 38 | } 39 | } 40 | return NULL; 41 | } 42 | 43 | // Find an empty pool slot 44 | static struct pool_entry *find_empty_slot(void) { 45 | for (int i = 0; i < MAX_POOLS; i++) { 46 | if (!gs_pools[i].in_use) { 47 | return &gs_pools[i]; 48 | } 49 | } 50 | return NULL; 51 | } 52 | 53 | int main(int argc, char *argv[]) { 54 | char input[256]; 55 | char command[32]; 56 | char pool_name[32]; 57 | int a, b, c; 58 | 59 | printf("Enter a command (type 'exit' to quit):\n"); 60 | 61 | while (1) { 62 | printf("> "); 63 | if (fgets(input, sizeof(input), stdin) == NULL) { 64 | printf("Error reading input. Exiting.\n"); 65 | break; 66 | } 67 | 68 | input[strcspn(input, "\n")] = '\0'; 69 | 70 | if (strcmp(input, "exit") == 0) { 71 | printf("Exiting program.\n"); 72 | break; 73 | } else if (strcmp(input, "help") == 0) { 74 | printf("%s", gs_help); 75 | continue; 76 | } else if (strcmp(input, "test") == 0) { 77 | z_thpool_test(); 78 | continue; 79 | } 80 | 81 | // Parse commands with pool name 82 | if (sscanf(input, "%s %s %d %d %d", command, pool_name, &a, &b, &c) >= 2) { 83 | if (strcmp(command, "create") == 0) { 84 | struct pool_entry *entry = find_empty_slot(); 85 | if (!entry) { 86 | printf("Error: Maximum number of pools reached\n"); 87 | continue; 88 | } 89 | 90 | struct z_thpool_config_struct config; 91 | config.max_thread_nums = a; 92 | config.msg_node_max = b; 93 | config.thread_stack_size = c * 1024; 94 | strncpy(config.pool_name, pool_name, sizeof(config.pool_name) - 1); 95 | config.pool_name[sizeof(config.pool_name) - 1] = '\0'; 96 | 97 | z_thpool_handle_t handle; 98 | if (z_thpool_create(&config, &handle) == 0) { 99 | strncpy(entry->name, pool_name, sizeof(entry->name) - 1); 100 | entry->name[sizeof(entry->name) - 1] = '\0'; 101 | entry->handle = handle; 102 | entry->in_use = 1; 103 | printf("Created thread pool '%s'\n", pool_name); 104 | } else { 105 | printf("Failed to create thread pool\n"); 106 | } 107 | } else { 108 | struct pool_entry *entry = find_pool(pool_name); 109 | if (!entry) { 110 | printf("Error: Pool '%s' not found\n", pool_name); 111 | continue; 112 | } 113 | 114 | if (strcmp(command, "destroy") == 0) { 115 | z_thpool_destroy(entry->handle); 116 | entry->in_use = 0; 117 | printf("Destroyed thread pool '%s'\n", pool_name); 118 | } else if (strcmp(command, "add") == 0) { 119 | for (int i = 0; i < a; i++) { 120 | if (z_thpool_add_work(entry->handle, test_task_cb, &i) != 0) { 121 | printf("Failed to add task %d\n", i); 122 | break; 123 | } 124 | printf("Added task %d to pool '%s'\n", i, pool_name); 125 | } 126 | } else if (strcmp(command, "show") == 0) { 127 | z_thpool_cmd_shell_show(entry->handle); 128 | } else { 129 | printf("%s", gs_help); 130 | } 131 | } 132 | } else { 133 | printf("%s", gs_help); 134 | } 135 | } 136 | 137 | // Cleanup any remaining pools 138 | for (int i = 0; i < MAX_POOLS; i++) { 139 | if (gs_pools[i].in_use) { 140 | z_thpool_destroy(gs_pools[i].handle); 141 | gs_pools[i].in_use = 0; 142 | } 143 | } 144 | z_tool_malloc_info(); 145 | return 0; 146 | } -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 |
2 | z_thpool 3 |

z_thpool

4 | English | 中文 5 |
6 | 7 |
8 |
9 | Featured|HelloGitHub 10 |
11 | 12 | ## ⚡ 简介 13 | 14 | **这是一个支持多实例的简单 Linux 线程池库。** 😊 15 | 16 | ## 💻 架构图 17 | 内部结构由多个线程池组成,每个线程池都有自己的循环队列。当线程池满时,新任务将被放入对应的循环队列中。当线程完成任务后,会从队列中获取新任务进行处理。 18 |
19 | z_thpool 20 |
21 | 22 | ## 🚀 如何使用? 23 | 24 | **以下操作都基于项目根目录,请确保正确执行!** 25 | 26 | ### **编译** 27 | 28 | ```bash 29 | cd z_thpool 30 | make 31 | cd lib 32 | ls 33 | libtestlib.a libz_thpool.a // 编译完成 34 | ``` 35 | 36 | ### **测试** 37 | 38 | #### 完整测试 39 | ```bash 40 | ./build/z_thpool_test 41 | 输入命令(输入 'exit' 退出): 42 | > help // 输入 help 查看测试命令 43 | 44 | 输入命令(输入 'exit' 退出): 45 | 46 | create pool1 5 100 64 # 创建名为 'pool1' 的线程池,5个线程,100个缓存队列,64k栈大小 47 | destroy pool1 # 销毁名为 'pool1' 的线程池 48 | add pool1 10 # 向 'pool1' 添加10个任务 49 | show pool1 # 显示 'pool1' 的状态 50 | test # 运行测试套件 51 | help # 显示帮助信息 52 | 53 | > test // 输入 test 检查完整测试情况 54 | 开始线程池极限测试... 55 | [debug ][src/z_thpool.c:182, z_thpool_create] enter 56 | [debug ][src/z_thpool.c:229, z_thpool_create] exit :0 57 | 任务 0 添加成功 58 | ... 59 | 任务 99 添加成功 60 | 等待中... 61 | 任务 0 正在被线程 140675616458496 处理 62 | ... 63 | 任务 99 正在被线程 140675609564928 处理 64 | 等待中... 65 | 等待中... 66 | 等待中... 67 | 等待中... 68 | 任务 0 处理后的参数: 0 69 | ... 70 | 任务 99 处理后的参数: 99 71 | 线程池极限测试完成。 72 | ``` 73 | 74 | #### 逐步测试 75 | ```bash 76 | ./build/z_thpool_test 77 | 输入命令(输入 'exit' 退出): 78 | > create pool1 5 100 64 // 创建名为 'pool1' 的线程池,5个线程,100个缓存队列,64K栈大小 79 | 线程池 'pool1' 创建成功 80 | 81 | > create pool2 3 50 64 // 创建另一个名为 'pool2' 的线程池 82 | 线程池 'pool2' 创建成功 83 | 84 | > add pool1 10 // 向pool1添加10个任务 85 | 向线程池 'pool1' 添加任务 0 86 | ... 87 | 向线程池 'pool1' 添加任务 9 88 | 89 | > show pool1 // 查看pool1状态 90 | ------------------------------------------------------------------------------------------------------------------------ 91 | | z_thpool 模块 92 | ------------------------------------------------------------------------------------------------------------------------ 93 | 版本: 0.0.2.0 94 | 线程池名称: pool1 95 | ------------------------------------------------------------------------------------------------------------------------ 96 | 最大线程数: 5 // 最大线程数为5 97 | 已创建线程数: 5 // 已创建5个线程 98 | 忙碌线程数: 5 // 当前有5个线程正在运行 99 | 最大缓存数: 100 // 创建了100个缓存队列 100 | 已用缓存数: 5 // 队列中等待的任务数 101 | 发布字节数: 200 102 | 订阅字节数: 0 103 | 104 | > destroy pool1 // 销毁pool1 105 | 线程池 'pool1' 已销毁 106 | ``` 107 | 108 | ### **使用方法** 109 | 使用线程池只需四个步骤: 110 | ```c 111 | // 步骤1:创建线程池配置 112 | struct z_thpool_config_struct config; 113 | config.max_thread_nums = 50; // 最大并发运行线程数为50 114 | config.msg_node_max = 1000; // 缓存队列最大容量为1000个任务 115 | config.thread_stack_size = 64 * 1024; // 每个线程的栈大小为64KB 116 | strncpy(config.pool_name, "pool1", sizeof(config.pool_name) - 1); // 为线程池命名 117 | 118 | // 步骤2:创建线程池 119 | z_thpool_handle_t handle; 120 | if (z_thpool_create(&config, &handle) == 0) { 121 | printf("线程池创建成功\n"); 122 | } 123 | 124 | // 步骤3:添加任务到线程池 125 | void task_callback(void *arg) { 126 | printf("正在处理任务: %d\n", *(int*)arg); 127 | } 128 | 129 | int task_arg = 1; 130 | if (z_thpool_add_work(handle, task_callback, &task_arg) == 0) { 131 | printf("任务添加成功\n"); 132 | } 133 | 134 | // 步骤4:完成后,销毁线程池 135 | z_thpool_destroy(handle); 136 | ``` 137 | 138 | ### **多线程池示例** 139 | ```c 140 | // 创建两个用于不同目的的线程池 141 | struct z_thpool_config_struct config1 = { 142 | .max_thread_nums = 5, 143 | .msg_node_max = 100, 144 | .thread_stack_size = 64 * 1024 145 | }; 146 | strncpy(config1.pool_name, "io_pool", sizeof(config1.pool_name) - 1); 147 | 148 | struct z_thpool_config_struct config2 = { 149 | .max_thread_nums = 10, 150 | .msg_node_max = 200, 151 | .thread_stack_size = 64 * 1024 152 | }; 153 | strncpy(config2.pool_name, "compute_pool", sizeof(config2.pool_name) - 1); 154 | 155 | z_thpool_handle_t io_pool, compute_pool; 156 | z_thpool_create(&config1, &io_pool); 157 | z_thpool_create(&config2, &compute_pool); 158 | 159 | // 使用不同的池处理不同的任务 160 | z_thpool_add_work(io_pool, io_task_callback, io_arg); 161 | z_thpool_add_work(compute_pool, compute_task_callback, compute_arg); 162 | 163 | // 完成后清理 164 | z_thpool_destroy(io_pool); 165 | z_thpool_destroy(compute_pool); 166 | ``` 167 | 168 | ### **文件说明** 169 | 主要文件包括: 170 | ```base 171 | test.c # 带命令行界面的测试程序 172 | z_kfifo.c # 循环队列实现 173 | z_thpool.c # 线程池实现 174 | z_debug.h # 调试信息开关 175 | z_tool.h # 工具宏 176 | z_table_print.c # 表格打印工具 177 | ``` 178 | 179 | ## 🛠️ 特性 180 | - 支持多线程池实例 181 | - 命名线程池便于管理 182 | - 每个池独立配置 183 | - 线程安全操作 184 | - 资源自动清理 185 | - 命令行测试接口 186 | 187 | ## 🛠️ 关于 188 | 189 | ## ❓ 常见问题 190 | 191 | ## 🤝 开发指南 192 | 193 | ## 🚀 Star趋势 194 | [![Stargazers over time](https://starchart.cc/BitStreamlet/z_thpool.svg?variant=adaptive)](https://starchart.cc/BitStreamlet/z_thpool) 195 | 196 | ## 🌟 贡献者 197 | 感谢所有为 z_thpool 做出贡献的人!🎉 198 | 199 | 200 | ## 🌟 致谢 201 | **感谢您花时间阅读我们的项目文档。** 202 | **如果您觉得这个项目有帮助,请给我们一个 Star。谢谢!** 203 | -------------------------------------------------------------------------------- /inc/z_tool.h: -------------------------------------------------------------------------------- 1 | #ifndef _Z_TOOL_H_ 2 | #define _Z_TOOL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | // Including standard libraries for various functionalities like networking, threading, etc. 9 | #include // Functions for IP address conversion 10 | #include // Defines the assert macro for debugging 11 | #include // Functions for directory operations 12 | #include // Error code definitions 13 | #include // File control options 14 | #include // Standard mathematical functions 15 | #include // Functions for interacting with MTD devices 16 | #include // Network database operations 17 | #include // Internet address family 18 | #include // Definitions related to TCP protocol 19 | #include // POSIX threads support 20 | #include // User database operations 21 | #include // Semaphore operations 22 | #include // Signal processing functions 23 | #include // Handling of variable arguments 24 | #include // Boolean type definitions 25 | #include // Common definitions, such as size_t 26 | #include // Standard integer types 27 | #include // Standard input/output functions 28 | #include // Standard library functions 29 | #include // String operations 30 | #include // Device control functions 31 | #include // Inter-process communication (IPC) mechanisms 32 | #include // Message queue operations 33 | #include // Process control functions 34 | #include // Socket interface 35 | #include // File status queries 36 | #include // Filesystem status queries 37 | #include // Time operations 38 | #include // System data type definitions 39 | #include // Basic system information 40 | #include // Terminal I/O control functions 41 | #include // Time operations 42 | #include // System call functions 43 | #include 44 | 45 | // Utility macros for stringifying and alignment operations 46 | #define Z_TOOL_STRINGIFY(x) #x 47 | #define Z_TOOL_TOSTRING(x) Z_TOOL_STRINGIFY(x) 48 | 49 | // Align a number up to the specified alignment 50 | #define Z_TOOL_ALIGN_UP(__num, __align) ((__num % __align) > 0 ? (__num + (__align - (__num % __align))) : __num) 51 | // Align a number down to the specified alignment 52 | #define Z_TOOL_ALIGN_DOWN(__num, __align) (__num - (__num % __align)) 53 | 54 | // Align the address or value to system's word size 55 | #define Z_TOOL_ALIGN_SYS(a) (((a) % sizeof(long)) ? ((a) + (sizeof(long) - ((a) % sizeof(long)))) : ((a))) 56 | 57 | // Macro to suppress unused variable warnings 58 | #define Z_TOOL_UNUSE_SET(x) (void)(x); 59 | 60 | // Macros for determining minimum and maximum of two values 61 | #define Z_TOOL_MIN(a, b) ((a) > (b) ? (b) : (a)) 62 | #define Z_TOOL_MAX(a, b) ((a) > (b) ? (a) : (b)) 63 | 64 | // Macros for mathematical operations 65 | /****************************************************************************** 66 | ** ABS(x) Absolute value of x 67 | ** SIGN(x) Sign of x 68 | ** CMP(x,y) 0 if x==y; 1 if x>y; -1 if x= 0 ? (x) : (-(x))) 71 | 72 | // Function to calculate the next power of two for a given number 73 | static inline uint32_t Z_TOOL_ROUNDUP_POW_OF_TWO(uint32_t n) { 74 | if (n == 0) return 1; 75 | n--; 76 | n |= n >> 1; 77 | n |= n >> 2; 78 | n |= n >> 4; 79 | n |= n >> 8; 80 | n |= n >> 16; 81 | return n + 1; 82 | } 83 | 84 | 85 | #define z_tool_malloc(sz) \ 86 | \ 87 | ({ \ 88 | static void *objp; \ 89 | objp = _z_tool_malloc((sz), (__FILE__), (__FUNCTION__), (__LINE__), &objp); \ 90 | objp; \ 91 | }) 92 | 93 | #define z_tool_free(objp) \ 94 | \ 95 | ({ \ 96 | if (objp) { \ 97 | _z_tool_free((objp), (__FILE__), (__FUNCTION__), (__LINE__)); \ 98 | } \ 99 | }) 100 | 101 | #define z_tool_realloc(old_objp, sz) \ 102 | \ 103 | ({ \ 104 | static void *objp; \ 105 | objp = _z_tool_realloc((old_objp), (sz), (__FILE__), (__FUNCTION__), (__LINE__), &objp); \ 106 | objp; \ 107 | }) 108 | 109 | #define z_tool_calloc(num, sz) \ 110 | \ 111 | ({ \ 112 | static void *objp; \ 113 | objp = _z_tool_calloc((num), (sz), (__FILE__), (__FUNCTION__), (__LINE__), &objp); \ 114 | objp; \ 115 | }) 116 | 117 | #define z_tool_strdup(s) \ 118 | \ 119 | ({ \ 120 | static void *objp; \ 121 | objp = _z_tool_strdup((s), (__FILE__), (__FUNCTION__), (__LINE__), &objp); \ 122 | objp; \ 123 | }) 124 | 125 | 126 | void *_z_tool_malloc(unsigned int size, const char *file, const char *function, unsigned int line, void *addr); 127 | void *_z_tool_realloc(void *old_ptr, unsigned int size, const char *file, const char *function, unsigned int line, void *addr); 128 | void _z_tool_free(void *ptr, const char *file, const char *function, unsigned int line); 129 | void *_z_tool_calloc(unsigned int num, unsigned int size, const char *file, const char *function, unsigned int line, void *addr); 130 | void *_z_tool_strdup(const char *s, const char *file, const char *function, unsigned int line, void *addr); 131 | void z_tool_malloc_info(void); 132 | 133 | #ifdef __cplusplus 134 | } 135 | #endif /* __cplusplus */ 136 | 137 | #endif /* _Z_TOOL_H_ */ 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | z_thpool 3 |

z_thpool

4 | English | 中文 5 |
6 | 7 |
8 |
9 | Featured|HelloGitHub 10 |
11 | 12 | ## ⚡ Introduction 13 | 14 | **This is a simple Linux thread pool library that supports multiple thread pool instances.** 😊 15 | 16 | ## 💻 Diagram 17 | The internal structure consists of multiple thread pools, each with its own circular queue. When a thread pool is full, new tasks will be placed in its circular queue. Once a thread exits, it will fetch a task from the queue for processing. 18 |
19 | z_thpool 20 |
21 | 22 | ## 🚀 How to use? 23 | 24 | **The following operations are based on the root directory of the current project, please ensure to perform them correctly!** 25 | 26 | ### **Compile** 27 | 28 | ```bash 29 | cd z_thpool 30 | make 31 | cd lib 32 | ls 33 | libtestlib.a libz_thpool.a // Compilation completed 34 | ``` 35 | 36 | ### **Test** 37 | 38 | #### Complete Test 39 | ```bash 40 | ./build/z_thpool_test 41 | Enter a command (type 'exit' to quit): 42 | > help // Enter help to view test commands 43 | 44 | Enter a command (type 'exit' to quit): 45 | 46 | create pool1 5 100 64 # Create pool named 'pool1' with 5 threads, 100 cache queues, 64k stack size 47 | destroy pool1 # Destroy pool named 'pool1' 48 | add pool1 10 # Add 10 tasks to pool named 'pool1' 49 | show pool1 # Show state of pool named 'pool1' 50 | test # Run test suite 51 | help # Show this help 52 | 53 | > test // Enter test to check complete test situation 54 | Starting thread pool extreme test... 55 | [debug ][src/z_thpool.c:182, z_thpool_create] enter 56 | [debug ][src/z_thpool.c:229, z_thpool_create] exit :0 57 | Task 0 added successfully 58 | ... 59 | Task 99 added successfully 60 | Waiting... 61 | Task 0 is being processed by thread 140675616458496 62 | ... 63 | Task 99 is being processed by thread 140675609564928 64 | Waiting... 65 | Waiting... 66 | Waiting... 67 | Waiting... 68 | Task 0 argument after processing: 0 69 | ... 70 | Task 99 argument after processing: 99 71 | Thread pool extreme test completed. 72 | ``` 73 | 74 | #### Step-by-Step Test 75 | ```bash 76 | ./build/z_thpool_test 77 | Enter a command (type 'exit' to quit): 78 | > create pool1 5 100 64 // Create a thread pool named 'pool1' with 5 threads, 100 cache queues, 64K stack size 79 | Created thread pool 'pool1' 80 | 81 | > create pool2 3 50 64 // Create another thread pool named 'pool2' 82 | Created thread pool 'pool2' 83 | 84 | > add pool1 10 // Add 10 tasks to pool1 85 | Added task 0 to pool 'pool1' 86 | ... 87 | Added task 9 to pool 'pool1' 88 | 89 | > show pool1 // View pool1 state 90 | ------------------------------------------------------------------------------------------------------------------------ 91 | | z_thpool module 92 | ------------------------------------------------------------------------------------------------------------------------ 93 | Ver: 0.0.2.0 94 | Pool Name: pool1 95 | ------------------------------------------------------------------------------------------------------------------------ 96 | max nums: 5 // Maximum threads is 5 97 | create nums: 5 // Threads already created is 5 98 | busy nums: 5 // Currently running threads is 5 99 | max cache nums: 100 // Created cache queue is 100 100 | use cache nums: 5 // Tasks waiting in the queue 101 | pub_bytes: 200 102 | sub_bytes: 0 103 | 104 | > destroy pool1 // Destroy pool1 105 | Destroyed thread pool 'pool1' 106 | ``` 107 | 108 | ### **Usage Functions** 109 | Just four steps to use the thread pool: 110 | ```c 111 | // Step 1: Create a thread pool configuration 112 | struct z_thpool_config_struct config; 113 | config.max_thread_nums = 50; // Maximum number of concurrently running threads is 50 114 | config.msg_node_max = 1000; // Maximum capacity of the cache queue is 1000 tasks 115 | config.thread_stack_size = 64 * 1024; // Stack size of each thread is 64KB 116 | strncpy(config.pool_name, "pool1", sizeof(config.pool_name) - 1); // Name your thread pool 117 | 118 | // Step 2: Create the thread pool 119 | z_thpool_handle_t handle; 120 | if (z_thpool_create(&config, &handle) == 0) { 121 | printf("Thread pool created successfully\n"); 122 | } 123 | 124 | // Step 3: Add tasks to the thread pool 125 | void task_callback(void *arg) { 126 | printf("Processing task: %d\n", *(int*)arg); 127 | } 128 | 129 | int task_arg = 1; 130 | if (z_thpool_add_work(handle, task_callback, &task_arg) == 0) { 131 | printf("Task added successfully\n"); 132 | } 133 | 134 | // Step 4: When done, destroy the thread pool 135 | z_thpool_destroy(handle); 136 | ``` 137 | 138 | ### **Multiple Thread Pools Example** 139 | ```c 140 | // Create two thread pools for different purposes 141 | struct z_thpool_config_struct config1 = { 142 | .max_thread_nums = 5, 143 | .msg_node_max = 100, 144 | .thread_stack_size = 64 * 1024 145 | }; 146 | strncpy(config1.pool_name, "io_pool", sizeof(config1.pool_name) - 1); 147 | 148 | struct z_thpool_config_struct config2 = { 149 | .max_thread_nums = 10, 150 | .msg_node_max = 200, 151 | .thread_stack_size = 64 * 1024 152 | }; 153 | strncpy(config2.pool_name, "compute_pool", sizeof(config2.pool_name) - 1); 154 | 155 | z_thpool_handle_t io_pool, compute_pool; 156 | z_thpool_create(&config1, &io_pool); 157 | z_thpool_create(&config2, &compute_pool); 158 | 159 | // Use different pools for different tasks 160 | z_thpool_add_work(io_pool, io_task_callback, io_arg); 161 | z_thpool_add_work(compute_pool, compute_task_callback, compute_arg); 162 | 163 | // Clean up when done 164 | z_thpool_destroy(io_pool); 165 | z_thpool_destroy(compute_pool); 166 | ``` 167 | 168 | ### **File Description** 169 | The key files are: 170 | ```base 171 | test.c # Test program with command line interface 172 | z_kfifo.c # Cache queue implementation 173 | z_thpool.c # Thread pool implementation 174 | z_debug.h # Debug information toggle 175 | z_tool.h # Tool macros 176 | z_table_print.c # Table printing utility 177 | ``` 178 | 179 | ## 🛠️ Features 180 | - Support for multiple thread pool instances 181 | - Named thread pools for better management 182 | - Independent configuration for each pool 183 | - Thread-safe operations 184 | - Resource cleanup on pool destruction 185 | - Command-line interface for testing 186 | 187 | ## 🛠️ About 188 | 189 | ## ❓ FAQ 190 | 191 | ## 🤝 Development Guide 192 | 193 | ## 🚀 Star 194 | [![Stargazers over time](https://starchart.cc/BitStreamlet/z_thpool.svg?variant=adaptive)](https://starchart.cc/BitStreamlet/z_thpool) 195 | 196 | ## 🌟 Contribution 197 | Thanks to everyone who has contributed to z_thpool! 🎉 198 | 199 | 200 | ## 🌟 Acknowledgment 201 | **Thank you for taking the time to read our project documentation.** 202 | **If you find this project helpful, please support us with a Star. Thank you!** -------------------------------------------------------------------------------- /src/z_kfifo.c: -------------------------------------------------------------------------------- 1 | #include "z_tool.h" 2 | #include "z_debug.h" 3 | #include "z_kfifo.h" 4 | 5 | // Initializes the kfifo structure with a buffer and its size. 6 | void z_kfifo_init(struct z_kfifo_struct *p_fifo, void *p_buffer, uint32_t size) { 7 | if (!p_fifo) return; // Exit if the fifo pointer is null. 8 | p_fifo->p_buffer = p_buffer; // Set the buffer pointer. 9 | p_fifo->size = size; // Set the size of the buffer. 10 | p_fifo->in = p_fifo->out = 0; // Initialize read and write pointers to zero. 11 | } 12 | 13 | // Allocates memory for the kfifo buffer and initializes the structure. 14 | int z_kfifo_malloc(struct z_kfifo_struct *p_fifo, uint32_t size) { 15 | if (!p_fifo) return -1; // Return error if fifo pointer is null. 16 | uint8_t *p_buffer; 17 | 18 | // Round up size to the nearest power of two if it's not already. 19 | if (size & (size - 1)) { 20 | size = Z_TOOL_ROUNDUP_POW_OF_TWO(size); 21 | } 22 | 23 | // Allocate memory for the buffer. 24 | p_buffer = (uint8_t *)z_tool_malloc(size); 25 | if (!p_buffer) { 26 | z_kfifo_init(p_fifo, NULL, 0); // Reset fifo if allocation fails. 27 | return -1; // Return error if memory allocation fails. 28 | } 29 | 30 | // Initialize fifo with allocated buffer and size. 31 | z_kfifo_init(p_fifo, p_buffer, size); 32 | return 0; // Return success. 33 | } 34 | 35 | // Frees the memory allocated for the kfifo buffer. 36 | void z_kfifo_free(struct z_kfifo_struct *p_fifo) { 37 | if (!p_fifo) return; // Exit if the fifo pointer is null. 38 | if (p_fifo->p_buffer) { 39 | z_tool_free(p_fifo->p_buffer); // Free the allocated buffer. 40 | } 41 | z_kfifo_init(p_fifo, NULL, 0); // Reset the fifo structure. 42 | } 43 | 44 | // Writes data into the kfifo buffer. 45 | uint32_t z_kfifo_in(struct z_kfifo_struct *p_fifo, const void *p_from, uint32_t len) { 46 | if (!p_fifo || !p_from) return 0; // Return zero if fifo or source pointer is null. 47 | uint32_t l, off; 48 | 49 | // Limit the length to the available space in the buffer. 50 | len = Z_TOOL_MIN(p_fifo->size - (p_fifo->in - p_fifo->out), len); 51 | off = p_fifo->in & (p_fifo->size - 1); // Calculate offset for circular buffer. 52 | 53 | // Determine how much data can be written in the first segment. 54 | l = Z_TOOL_MIN(len, p_fifo->size - off); 55 | memcpy(p_fifo->p_buffer + off, p_from, l); // Write to the buffer. 56 | 57 | // Write remaining data if the buffer wraps around. 58 | memcpy(p_fifo->p_buffer, (char *)p_from + l, len - l); 59 | p_fifo->in += len; // Update the write pointer. 60 | return len; // Return the number of bytes written. 61 | } 62 | 63 | // Reads data from the kfifo buffer. 64 | uint32_t z_kfifo_out(struct z_kfifo_struct *p_fifo, void *p_to, uint32_t len) { 65 | if (!p_fifo || !p_to) return 0; // Return zero if fifo or destination pointer is null. 66 | uint32_t off, l; 67 | 68 | // Limit the length to the available data in the buffer. 69 | len = Z_TOOL_MIN(p_fifo->in - p_fifo->out, len); 70 | off = p_fifo->out & (p_fifo->size - 1); // Calculate offset for circular buffer. 71 | 72 | // Determine how much data can be read in the first segment. 73 | l = Z_TOOL_MIN(len, p_fifo->size - off); 74 | memcpy(p_to, p_fifo->p_buffer + off, l); // Read from the buffer. 75 | 76 | // Read remaining data if the buffer wraps around. 77 | memcpy((char *)p_to + l, p_fifo->p_buffer, len - l); 78 | p_fifo->out += len; // Update the read pointer. 79 | return len; // Return the number of bytes read. 80 | } 81 | 82 | // Checks the number of bytes available to read from the kfifo. 83 | uint32_t z_kfifo_out_check(struct z_kfifo_struct *p_fifo, void *p_to, uint32_t len) { 84 | if (!p_fifo || !p_to) return 0; // Return zero if fifo or destination pointer is null. 85 | uint32_t off, l; 86 | 87 | // Limit the length to the available data in the buffer. 88 | len = Z_TOOL_MIN(p_fifo->in - p_fifo->out, len); 89 | off = p_fifo->out & (p_fifo->size - 1); // Calculate offset for circular buffer. 90 | 91 | // Determine how much data can be read in the first segment. 92 | l = Z_TOOL_MIN(len, p_fifo->size - off); 93 | memcpy(p_to, p_fifo->p_buffer + off, l); // Read from the buffer. 94 | 95 | // Read remaining data if the buffer wraps around. 96 | memcpy((char *)p_to + l, p_fifo->p_buffer, len - l); 97 | return len; // Return the number of bytes read. 98 | } 99 | 100 | // Returns the amount of free space in the kfifo. 101 | uint32_t z_kfifo_space(struct z_kfifo_struct *p_fifo) { 102 | if (!p_fifo) return 0; // Return zero if fifo pointer is null. 103 | return p_fifo->size - (p_fifo->in - p_fifo->out); // Calculate available space. 104 | } 105 | 106 | // Returns the amount of data currently stored in the kfifo. 107 | uint32_t z_kfifo_data_len(struct z_kfifo_struct *p_fifo) { 108 | if (!p_fifo) return 0; // Return zero if fifo pointer is null. 109 | return p_fifo->in - p_fifo->out; // Calculate the length of stored data. 110 | } 111 | 112 | // Tests various functionalities of the kfifo. 113 | uint32_t z_kfifo_test(void) { 114 | // Define the buffer size and initialize test data. 115 | const uint32_t buffer_size = 16; 116 | uint8_t test_data_in[buffer_size]; 117 | uint8_t test_data_out[buffer_size]; 118 | 119 | for (uint32_t i = 0; i < buffer_size; i++) { 120 | test_data_in[i] = i; // Fill test data with sequential values. 121 | } 122 | 123 | // Define kfifo structure and zero-initialize it. 124 | struct z_kfifo_struct fifo; 125 | memset(&fifo, 0, sizeof(fifo)); 126 | 127 | // Test memory allocation for the kfifo. 128 | if (z_kfifo_malloc(&fifo, buffer_size) != 0) { 129 | Z_RAW("Memory allocation failed\n"); 130 | return -1; // Return error if memory allocation fails. 131 | } 132 | 133 | // Test writing data into the kfifo. 134 | uint32_t written = z_kfifo_in(&fifo, test_data_in, buffer_size); 135 | if (written != buffer_size) { 136 | Z_RAW("Data write failed, written: %u\n", written); 137 | z_kfifo_free(&fifo); 138 | return -1; // Return error if the write operation fails. 139 | } 140 | 141 | // Test reading data from the kfifo. 142 | uint32_t read = z_kfifo_out(&fifo, test_data_out, buffer_size); 143 | if (read != buffer_size) { 144 | Z_RAW("Data read failed, read: %u\n", read); 145 | z_kfifo_free(&fifo); 146 | return -1; // Return error if the read operation fails. 147 | } 148 | 149 | // Verify that the read data matches the written data. 150 | for (uint32_t i = 0; i < buffer_size; i++) { 151 | if (test_data_out[i] != test_data_in[i]) { 152 | Z_RAW("Data mismatch at index %u, expected: %u, got: %u\n", i, test_data_in[i], test_data_out[i]); 153 | z_kfifo_free(&fifo); 154 | return -1; // Return error if there is a data mismatch. 155 | } 156 | } 157 | 158 | // Test writing to a full kfifo. 159 | written = z_kfifo_in(&fifo, test_data_in, buffer_size); 160 | if (written != buffer_size) { 161 | Z_RAW("Buffer full test failed, written: %u\n", written); 162 | z_kfifo_free(&fifo); 163 | return -1; // Return error if writing to full buffer fails. 164 | } 165 | 166 | // Test reading from an empty kfifo. 167 | read = z_kfifo_out(&fifo, test_data_out, buffer_size); 168 | if (read != buffer_size) { 169 | Z_RAW("Buffer empty test failed, read: %u\n", read); 170 | z_kfifo_free(&fifo); 171 | return -1; // Return error if reading from empty buffer fails. 172 | } 173 | 174 | // Test freeing memory allocated for the kfifo. 175 | z_kfifo_free(&fifo); 176 | if (fifo.p_buffer != NULL || fifo.size != 0 || fifo.in != 0 || fifo.out != 0) { 177 | Z_RAW("Memory free failed\n"); 178 | return -1; // Return error if memory was not freed correctly. 179 | } 180 | 181 | Z_RAW("All tests passed successfully\n"); 182 | return 0; // Return success if all tests pass. 183 | } 184 | -------------------------------------------------------------------------------- /inc/z_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _Z_DEBUG_ 2 | #define _Z_DEBUG_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | #define E_LEVEL_COLOR_ESC_START "\033[" 9 | #define E_LEVEL_COLOR_ESC_END "\033[0m" 10 | #define E_LEVEL_COLOR_FATAL "1;31;40m" // Bold Red text on a black background 11 | #define E_LEVEL_COLOR_ERROR "1;35;40m" // Bold Magenta text on a black background 12 | #define E_LEVEL_COLOR_WARN "1;33;40m" // Bold Yellow text on a black background 13 | #define E_LEVEL_COLOR_NOTICE "1;34;40m" // Bold Blue text on a black background 14 | #define E_LEVEL_COLOR_INFO "1;32;40m" // Bold Green text on a black background 15 | #define E_LEVEL_COLORRE_DEBUG "1;36;40m" // Bold Cyan text on a black background 16 | #define E_LINE_MODE "\r\n" 17 | 18 | enum z_level_enum { 19 | E_Z_DEBUG_LEVEL_PRINTF = -1, 20 | E_Z_DEBUG_LEVEL_RAW = 0, 21 | E_Z_DEBUG_LEVEL_FATAL, 22 | E_Z_DEBUG_LEVEL_ERROR, 23 | E_Z_DEBUG_LEVEL_WARN, 24 | E_Z_DEBUG_LEVEL_NOTICE, 25 | E_Z_DEBUG_LEVEL_INFO, 26 | E_Z_DEBUG_LEVEL_DEBUG, 27 | E_Z_DEBUG_LEVEL_MAX 28 | }; 29 | #define _Z_DEBUG(_level, format, args...) \ 30 | while (1) { \ 31 | switch (_level) { \ 32 | case E_Z_DEBUG_LEVEL_FATAL: \ 33 | printf("[fatal ][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLOR_FATAL format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 34 | fflush(stdout); \ 35 | break; \ 36 | case E_Z_DEBUG_LEVEL_ERROR: \ 37 | printf("[error ][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLOR_ERROR format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 38 | fflush(stdout); \ 39 | break; \ 40 | case E_Z_DEBUG_LEVEL_WARN: \ 41 | printf("[wart ][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLOR_WARN format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 42 | fflush(stdout); \ 43 | break; \ 44 | case E_Z_DEBUG_LEVEL_NOTICE: \ 45 | printf("[notice][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLOR_NOTICE format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 46 | fflush(stdout); \ 47 | break; \ 48 | case E_Z_DEBUG_LEVEL_INFO: \ 49 | printf("[info ][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLOR_INFO format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 50 | fflush(stdout); \ 51 | break; \ 52 | case E_Z_DEBUG_LEVEL_DEBUG: \ 53 | printf("[debug ][%s:%d, %s] " E_LEVEL_COLOR_ESC_START E_LEVEL_COLORRE_DEBUG format E_LEVEL_COLOR_ESC_END E_LINE_MODE, __FILE__, __LINE__, __FUNCTION__, ##args); \ 54 | fflush(stdout); \ 55 | break; \ 56 | case E_Z_DEBUG_LEVEL_RAW: \ 57 | case E_Z_DEBUG_LEVEL_PRINTF: \ 58 | printf(format, ##args); \ 59 | fflush(stdout); \ 60 | break; \ 61 | default: \ 62 | break; \ 63 | } \ 64 | break; \ 65 | } 66 | 67 | #define Z_DEBUG(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_DEBUG, format, ##args) 68 | #define Z_ERROR(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_ERROR, format, ##args) 69 | #define Z_WARN(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_WARN, format, ##args) 70 | #define Z_NOTICE(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_NOTICE, format, ##args) 71 | #define Z_FATAL(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_FATAL, format, ##args) 72 | #define Z_INFO(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_INFO, format, ##args) 73 | #define Z_RAW(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_RAW, format, ##args) 74 | #define Z_PRINTF(format, args...) _Z_DEBUG(E_Z_DEBUG_LEVEL_PRINTF, format, ##args) 75 | #define Z_DEBUG_ENTER() _Z_DEBUG(E_Z_DEBUG_LEVEL_DEBUG, "enter"); 76 | #define Z_DEBUG_EXIT(_ret) _Z_DEBUG(E_Z_DEBUG_LEVEL_DEBUG, "exit :%d", _ret); 77 | 78 | #define Z_BASE_ASSERT(condition) \ 79 | int *p = NULL; \ 80 | while (1) { \ 81 | *p = 0x5a5a5a5a; \ 82 | assert(0); \ 83 | } 84 | 85 | //_ASSERT(0):就会终止 86 | #define Z_ASSERT(condition) \ 87 | do { \ 88 | if (!(condition)) { \ 89 | Z_FATAL("ASSERT: Condition '%s' is true !", #condition); \ 90 | Z_BASE_ASSERT(condition); \ 91 | } \ 92 | } while (0) 93 | 94 | #define Z_WARN_ON(condition) \ 95 | do { \ 96 | if (condition) { \ 97 | Z_WARN("WARNING: Condition '%s' is true!", #condition); \ 98 | } \ 99 | } while (0) 100 | 101 | #define Z_WARN_ON_ONCE(condition) \ 102 | do { \ 103 | static int __warned = 0; \ 104 | if (!__warned && (condition)) { \ 105 | Z_WARN("WARNING: Condition '%s' is true!", #condition); \ 106 | __warned = 1; \ 107 | } \ 108 | } while (0) 109 | 110 | #define Z_BUG() \ 111 | do { \ 112 | z("BUG: failure!"); \ 113 | z("BUG!"); \ 114 | } while (0) 115 | 116 | #define Z_BUG_ON(condition) \ 117 | do { \ 118 | if ((condition)) { \ 119 | z("BUG: Condition '%s' is true !", #condition); \ 120 | Z_BASE_ASSERT(condition); \ 121 | } \ 122 | } while (0) 123 | 124 | // 测试断言宏 125 | #define Z_ASSERT_TEST(condition, message) \ 126 | if (!(condition)) { \ 127 | Z_ERROR("Test failed: %s", (message)); \ 128 | } else { \ 129 | Z_ERROR("Test passed: %s", (message)); \ 130 | } 131 | 132 | #define Z_DEBUG_THREAD_SET_TRACE(func) \ 133 | do { \ 134 | char tmp[16]; \ 135 | snprintf(tmp, sizeof(tmp), "%p", func); \ 136 | prctl(PR_SET_NAME, (unsigned long)tmp, 0, 0, 0); \ 137 | } while (0); 138 | #define Z_DEBUG_THREAD_CALL_INFO() 139 | #define Z_DEBUG_THREAD_CALL_INFO_FREE() 140 | 141 | #ifdef __cplusplus 142 | } 143 | #endif /* __cplusplus */ 144 | 145 | #endif /* _Z_CONFIG_H_ */ 146 | -------------------------------------------------------------------------------- /src/z_thpool.c: -------------------------------------------------------------------------------- 1 | #include "z_tool.h" 2 | #include "z_kfifo.h" 3 | #include "z_debug.h" 4 | #include "z_thpool.h" 5 | #include "z_table_print.h" 6 | 7 | 8 | #define Z_THPOOL_VERION "0.0.3.0" 9 | 10 | // Structure to hold thread pool message details 11 | struct z_thpool_msg_struct { 12 | void (*cb)(void *); // Callback function 13 | void *p_arg; // Argument to the callback function 14 | }; 15 | 16 | // Structure for managing the thread pool 17 | struct z_thpool_mng_struct { 18 | int32_t start_flag; // Flag indicating if the thread pool is started 19 | struct z_kfifo_struct t_info; // Information management for message queue 20 | int32_t th_run_flag; // Flag controlling thread pool run state 21 | uint32_t th_run_nums; // Number of currently running threads 22 | uint32_t th_busy_nums; // Number of busy threads 23 | uint32_t max_nums; // Maximum number of threads allowed 24 | uint32_t msg_node_max; // Maximum number of message nodes 25 | pthread_mutex_t mutex; // Mutex for synchronization 26 | pthread_cond_t cond; // Condition variable for thread synchronization 27 | uint32_t pub_bytes; // Data published (for statistics) 28 | uint32_t sub_bytes; // Data consumed (for statistics) 29 | struct z_thpool_config_struct t_config; // Configuration for thread pool 30 | char pool_name[32]; // Name of the thread pool 31 | }; 32 | 33 | // Global variables for thread pool management and synchronization 34 | static struct z_thpool_mng_struct gs_thpool_mng = {0}; 35 | static pthread_mutex_t gs_thpool_mutex = PTHREAD_MUTEX_INITIALIZER; 36 | static int32_t z_thpool_cmd(void); 37 | 38 | // Static function declarations 39 | static int32_t z_thpool_create_thread(pthread_t *p_pth, void *(*func)(void *), void *p_arg, uint32_t stack_size); 40 | static void z_thpool_msg_read(void *param); 41 | static void *z_thpool_proc(void *param); 42 | 43 | /** 44 | @brief Create a new thread pool instance 45 | @param p_config Configuration parameters for the thread pool 46 | @param p_handle Pointer to store the created thread pool handle 47 | @return Status of thread pool creation, success is 0 48 | */ 49 | int32_t z_thpool_create(struct z_thpool_config_struct *p_config, z_thpool_handle_t *p_handle) { 50 | Z_DEBUG_ENTER(); 51 | int32_t ret = -1; 52 | 53 | if (!p_config || !p_handle) { 54 | goto error0; 55 | } 56 | 57 | struct z_thpool_mng_struct *p_mng = (struct z_thpool_mng_struct *)z_tool_malloc(sizeof(struct z_thpool_mng_struct)); 58 | if (!p_mng) { 59 | goto error0; 60 | } 61 | memset(p_mng, 0, sizeof(struct z_thpool_mng_struct)); 62 | 63 | // Initialize mutex and condition variable 64 | if (pthread_mutex_init(&p_mng->mutex, NULL) != 0) { 65 | goto error1; 66 | } 67 | 68 | if (pthread_cond_init(&p_mng->cond, NULL) != 0) { 69 | goto error2; 70 | } 71 | 72 | // Initialize FIFO queue 73 | ret = z_kfifo_malloc(&p_mng->t_info, sizeof(struct z_thpool_msg_struct) * p_config->msg_node_max); 74 | if (ret != 0) { 75 | goto error3; 76 | } 77 | 78 | // Copy configuration 79 | memcpy(&p_mng->t_config, p_config, sizeof(struct z_thpool_config_struct)); 80 | strncpy(p_mng->pool_name, p_config->pool_name, sizeof(p_mng->pool_name) - 1); 81 | p_mng->pool_name[sizeof(p_mng->pool_name) - 1] = '\0'; 82 | 83 | p_mng->max_nums = p_config->max_thread_nums; 84 | p_mng->msg_node_max = p_config->msg_node_max; 85 | p_mng->th_run_flag = 1; 86 | 87 | // Create worker threads 88 | for (uint32_t i = 0; i < p_config->max_thread_nums; i++) { 89 | pthread_t tid; 90 | ret = z_thpool_create_thread(&tid, z_thpool_proc, p_mng, p_config->thread_stack_size); 91 | if (ret != 0) { 92 | p_mng->th_run_flag = 0; 93 | pthread_cond_broadcast(&p_mng->cond); 94 | while (p_mng->th_run_nums > 0) { 95 | usleep(10000); 96 | } 97 | goto error4; 98 | } 99 | p_mng->th_run_nums++; 100 | } 101 | 102 | p_mng->start_flag = 1; 103 | *p_handle = p_mng; 104 | ret = 0; 105 | Z_DEBUG_EXIT(0); 106 | return ret; 107 | 108 | error4: 109 | z_kfifo_free(&p_mng->t_info); 110 | error3: 111 | pthread_cond_destroy(&p_mng->cond); 112 | error2: 113 | pthread_mutex_destroy(&p_mng->mutex); 114 | error1: 115 | z_tool_free(p_mng); 116 | error0: 117 | Z_DEBUG_EXIT(ret); 118 | return ret; 119 | } 120 | 121 | /** 122 | @brief Destroy a thread pool instance 123 | @param handle Handle to the thread pool to destroy 124 | @return Status of thread pool destruction, success is 0 125 | */ 126 | int32_t z_thpool_destroy(z_thpool_handle_t handle) { 127 | Z_DEBUG_ENTER(); 128 | int32_t ret = -1; 129 | 130 | if (!handle) { 131 | goto error0; 132 | } 133 | 134 | struct z_thpool_mng_struct *p_mng = (struct z_thpool_mng_struct *)handle; 135 | 136 | pthread_mutex_lock(&p_mng->mutex); 137 | if (!p_mng->start_flag) { 138 | pthread_mutex_unlock(&p_mng->mutex); 139 | goto error0; 140 | } 141 | 142 | p_mng->th_run_flag = 0; 143 | pthread_cond_broadcast(&p_mng->cond); 144 | pthread_mutex_unlock(&p_mng->mutex); 145 | 146 | // Wait for all threads to exit 147 | while (p_mng->th_run_nums > 0) { 148 | usleep(10000); 149 | } 150 | 151 | // Cleanup resources 152 | z_kfifo_free(&p_mng->t_info); 153 | pthread_mutex_destroy(&p_mng->mutex); 154 | pthread_cond_destroy(&p_mng->cond); 155 | z_tool_free(p_mng); 156 | 157 | ret = 0; 158 | Z_DEBUG_EXIT(0); 159 | return ret; 160 | 161 | error0: 162 | Z_DEBUG_EXIT(ret); 163 | return ret; 164 | } 165 | 166 | /** 167 | @brief Create a thread, set its attributes, and start it 168 | @param p_pth Pointer to the thread ID 169 | @param func Function to be executed by the thread 170 | @param p_arg Argument passed to the function 171 | @param stack_size Stack size for the thread 172 | @return Status of thread creation, success is 0 173 | */ 174 | static int32_t z_thpool_create_thread(pthread_t *p_pth, void *(*func)(void *), void *p_arg, uint32_t stack_size) { 175 | int32_t ret; 176 | pthread_attr_t attr; 177 | 178 | pthread_attr_init(&attr); 179 | 180 | // Set the thread to be detached 181 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 182 | pthread_attr_setstacksize(&attr, stack_size); 183 | 184 | #ifndef CFG_PLATFORM_X86 185 | // Set explicit scheduling if not on X86 platform 186 | ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); 187 | if (ret) { 188 | fprintf(stderr, "pthread_attr_setinheritsched:%d\n", ret); 189 | goto error; 190 | } 191 | #endif 192 | 193 | // Create the thread with specified attributes 194 | ret = pthread_create(p_pth, &attr, func, p_arg); 195 | if (ret) { 196 | fprintf(stderr, "pthread_create:%d\n", ret); 197 | goto error; 198 | } 199 | 200 | error: 201 | // Clean up thread attributes 202 | pthread_attr_destroy(&attr); 203 | return ret; 204 | } 205 | 206 | /** 207 | @brief Read and process messages from the message queue 208 | @param param Pointer to the thread pool management structure 209 | @return No return value 210 | */ 211 | static void z_thpool_msg_read(void *param) { 212 | struct z_thpool_mng_struct *mng = (struct z_thpool_mng_struct *)param; 213 | struct z_thpool_msg_struct msg; 214 | 215 | pthread_mutex_lock(&mng->mutex); 216 | while (mng->th_run_flag && z_kfifo_data_len(&mng->t_info) < sizeof(struct z_thpool_msg_struct)) { 217 | pthread_cond_wait(&mng->cond, &mng->mutex); 218 | } 219 | 220 | if (mng->th_run_flag == 0 || z_kfifo_data_len(&mng->t_info) < sizeof(struct z_thpool_msg_struct)) { 221 | pthread_mutex_unlock(&mng->mutex); 222 | return; 223 | } 224 | 225 | // Retrieve message from the queue 226 | uint32_t len = z_kfifo_out(&mng->t_info, &msg, sizeof(struct z_thpool_msg_struct)); 227 | mng->th_busy_nums++; 228 | mng->sub_bytes += len; 229 | pthread_mutex_unlock(&mng->mutex); 230 | 231 | // Execute the callback function for the message 232 | msg.cb(msg.p_arg); 233 | 234 | pthread_mutex_lock(&mng->mutex); 235 | mng->th_busy_nums--; 236 | pthread_mutex_unlock(&mng->mutex); 237 | } 238 | 239 | /** 240 | @brief Thread pool processing function 241 | @param param Pointer to the thread pool management structure 242 | @return No return value 243 | */ 244 | static void *z_thpool_proc(void *param) { 245 | prctl(PR_SET_NAME, "thp"); 246 | struct z_thpool_mng_struct *mng = (struct z_thpool_mng_struct *)param; 247 | 248 | // Continue processing messages as long as the run flag is set 249 | while (mng->th_run_flag) { 250 | z_thpool_msg_read(mng); 251 | } 252 | 253 | // Decrement the run number after processing is complete 254 | pthread_mutex_lock(&mng->mutex); 255 | mng->th_run_nums--; 256 | pthread_mutex_unlock(&mng->mutex); 257 | return NULL; 258 | } 259 | 260 | /** 261 | @brief Add a work task to the thread pool 262 | @param handle Handle to the thread pool 263 | @param cb Callback function 264 | @param p_arg Argument for the callback function 265 | @return Status, success is 0 266 | */ 267 | int32_t z_thpool_add_work(z_thpool_handle_t handle, void (*cb)(void *), void *p_arg) { 268 | if (!handle || !cb || !p_arg) { 269 | return -EINVAL; 270 | } 271 | 272 | struct z_thpool_mng_struct *p_mng = (struct z_thpool_mng_struct *)handle; 273 | int32_t ret = -1; 274 | 275 | pthread_mutex_lock(&p_mng->mutex); 276 | if (!p_mng->start_flag) { 277 | goto error; 278 | } 279 | 280 | if (z_kfifo_space(&p_mng->t_info) < sizeof(struct z_thpool_msg_struct)) { 281 | goto error; 282 | } 283 | 284 | struct z_thpool_msg_struct msg; 285 | msg.cb = cb; 286 | msg.p_arg = p_arg; 287 | 288 | uint32_t len = z_kfifo_in(&p_mng->t_info, &msg, sizeof(struct z_thpool_msg_struct)); 289 | if (len != sizeof(struct z_thpool_msg_struct)) { 290 | goto error; 291 | } 292 | 293 | p_mng->pub_bytes += len; 294 | pthread_cond_signal(&p_mng->cond); 295 | ret = 0; 296 | 297 | error: 298 | pthread_mutex_unlock(&p_mng->mutex); 299 | return ret; 300 | } 301 | 302 | /** 303 | @brief Display thread pool status 304 | @param handle Handle to the thread pool 305 | @return Status, success is 0 306 | */ 307 | int32_t z_thpool_cmd_shell_show(z_thpool_handle_t handle) { 308 | if (!handle) { 309 | return -EINVAL; 310 | } 311 | 312 | struct z_thpool_mng_struct *p_mng = (struct z_thpool_mng_struct *)handle; 313 | pthread_mutex_lock(&p_mng->mutex); 314 | 315 | z_table_print_title("z_thpool module"); 316 | z_table_print_row("%-18s %s\n", "Ver: ", Z_THPOOL_VERION); 317 | z_table_print_row("%-18s %s\n", "Pool Name: ", p_mng->pool_name); 318 | z_table_print_border(); 319 | z_table_print_row("%-18s %d\n", "max nums: ", p_mng->max_nums); 320 | z_table_print_row("%-18s %d\n", "create nums: ", p_mng->th_run_nums); 321 | z_table_print_row("%-18s %d\n", "busy nums:", p_mng->th_busy_nums); 322 | z_table_print_row("%-18s %d\n", "max cache nums:", p_mng->msg_node_max); 323 | z_table_print_row("%-18s %d\n", "use cache nums:", 324 | z_kfifo_data_len(&p_mng->t_info) / sizeof(struct z_thpool_msg_struct)); 325 | z_table_print_row("%-18s %d\n", "pub_bytes:", p_mng->pub_bytes); 326 | z_table_print_row("%-18s %d\n", "sub_bytes:", p_mng->sub_bytes); 327 | 328 | pthread_mutex_unlock(&p_mng->mutex); 329 | return 0; 330 | } 331 | 332 | /** 333 | @brief Task callback function 334 | @param p_arg Parameter 335 | @return No return value 336 | */ 337 | static void z_thpool_test_task_cb(void *p_arg) { 338 | int32_t num = *((int32_t *)p_arg); 339 | printf("Task %d is being processed by thread %lu\n", num, pthread_self()); 340 | sleep(1); // Simulate task processing time 341 | } 342 | 343 | /** 344 | @brief Test the thread pool functionality 345 | @return Status, success is 0 346 | */ 347 | int32_t z_thpool_test(void) { 348 | // Configuration for the thread pool extreme test 349 | struct z_thpool_config_struct t_config = { 350 | .max_thread_nums = 100, 351 | .msg_node_max = 100, 352 | .thread_stack_size = 64 * 1024 353 | }; 354 | strncpy(t_config.pool_name, "test_pool", sizeof(t_config.pool_name) - 1); 355 | t_config.pool_name[sizeof(t_config.pool_name) - 1] = '\0'; 356 | 357 | printf("Starting thread pool extreme test...\n"); 358 | 359 | // Create thread pool 360 | z_thpool_handle_t handle; 361 | if (z_thpool_create(&t_config, &handle) != 0) { 362 | printf("Failed to create thread pool\n"); 363 | return -1; 364 | } 365 | 366 | // Define task parameters array 367 | int32_t task_args[100]; 368 | for (int32_t i = 0; i < 100; i++) { 369 | task_args[i] = i; 370 | } 371 | 372 | // Add tasks to the thread pool 373 | for (int32_t i = 0; i < 100; i++) { 374 | if (z_thpool_add_work(handle, z_thpool_test_task_cb, &task_args[i]) != 0) { 375 | fprintf(stderr, "Failed to add task %d\n", i); 376 | } else { 377 | printf("Task %d added successfully\n", i); 378 | } 379 | } 380 | 381 | // Wait for tasks to be processed 382 | for (int32_t i = 0; i < 5; i++) { 383 | printf("Waiting...\n"); 384 | sleep(1); 385 | } 386 | 387 | // Verify data integrity 388 | for (int32_t i = 0; i < 100; i++) { 389 | printf("Task %d argument after processing: %d\n", i, task_args[i]); 390 | } 391 | 392 | // Show thread pool status 393 | z_thpool_cmd_shell_show(handle); 394 | 395 | // Destroy the thread pool 396 | z_thpool_destroy(handle); 397 | printf("Thread pool extreme test completed.\n"); 398 | return 0; 399 | } 400 | --------------------------------------------------------------------------------