c入门第二十五篇: 学生成绩管理系统优化(多线程)

前言

程夏:“你这个系统不好用啊?连上之后没有反应,是不是挂了?”
客户端程序
师弟:“不应该啊,我这边好好的,可以正常操作的。”
客户端程序
程夏:“我这边有问题,大概率还是你系统问题。你再测试一下吧。”
师弟:“额,基本的功能我都测试过了的。”
程夏:“多客户端请求呢?一些边界场景、一些异常场景都有测试么?”
师弟瞬时陷入沉思,难道是多客户端操作存在问题。
师弟紧急复现了一下这个问题,发现服务端,最多处理一个客户端的请求,其他请求阻塞住了。
如何支持多客户端的请求呢?

多线程

在c语言中可以通过 pthread_create 函数来实现多线程的创建。主要代码处理逻辑片段如下。在主线程中创建完处理线程之后,主线程继续执行后面的逻辑,不会被阻塞,客户端的请求则被新线程处理。好比汽车维修的接待和技术维修,如果是同一个人,则同时只能进行一辆车的处理,但是如果接待是一个人和维修是多个人,接待完分发给维修处理之后,继续接待,则可以进行多辆车的处理。多线程的优点是,在cpu多核架构中,能够充分利用多个核心的并发处理来提交程序的效率。

    while (1) {// Accept a connectionif ((conn_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 启动线程去处理数据ret = pthread_create(&thread, NULL, do_data_process, &conn_fd);if (ret) {printf("pthread_create failed, ret:%d\n", ret);exit(EXIT_FAILURE);}}

多线程

系统完整代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for access() function
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"
#define TRUE 1
#define FALSE 0
#define BUF_SIZE 1024char *welcome_info = "\nWelcome to Student Score Management System\n"\"0. Exit\n"\"1. Add Student\n"\"2. Display All Students\n"\"3. Find Student by ID\n"\"4. Find Student by Name\n"\"5. Add Score\n"\"6. Display Average Score\n"\"7. Display by Score sort\n"\"Enter your choice: ";typedef struct {int id; // 学号char name[MAX_NAME_LEN]; // 姓名float score; // 成绩
} Student;int student_count = 0; // 学生数量Student *students; // 学生数组指针
int g_max_student = MAX_STUDENTS;Student *stu_sys_init(int num)
{Student *stu_sys;stu_sys = malloc(num * sizeof(Student));if (stu_sys == NULL) {printf("student system malloc failed!\n");}return stu_sys;
}int write_student_info(Student *s)
{FILE *fp = fopen(STUDENT_SYSTEM, "a");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);fclose(fp);return 0;
}int check_if_student_exsit(int id)
{int i;for(i = 0; i < student_count; i++) {if(students[i].id == id) {return 1;}}return 0;
}void update_student_info(Student s, int need_write)
{Student *stu_reinit;int old_max_student;if(student_count >= g_max_student) {old_max_student = g_max_student;g_max_student = g_max_student << 1;stu_reinit = stu_sys_init(g_max_student);if (stu_reinit == NULL) {printf("Database is full!\n");return;}memcpy(stu_reinit, students, old_max_student * sizeof(Student));free(students);students = stu_reinit;}if (!check_if_student_exsit(s.id)) {students[student_count++] = s;if (need_write) {printf("Student added successfully, all student: %d!\n", student_count);write_student_info(&s);}} else {printf("student has in db, do nothing!\n");}
}void add_student()
{Student s;printf("Enter student ID: ");scanf("%d", &s.id);printf("Enter student name: ");scanf("%s", s.name);s.score = 0.0; // 初始成绩设置为0update_student_info(s, TRUE);
}void print_title()
{printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}void display_all_students()
{int i;printf("-------- All students info --------\n");if (student_count == 0) {printf("No students!\n");} else {print_title();for(i = 0; i < student_count; i++) {printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);}}printf("--------      End       -----------\n");
}/*** @arr: 有序数组* @l: 待查找区间左端点* @r: 待查找区间右端点* @target: 需要查找的元素*/
int binary_search(Student *s, int l, int r, int target)
{int m;while (l <= r) {// 计算中间位置m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出// 检查x是否存在于中间位置if (s[m].id == target)return m;// 若x大,则忽略左半部分if (s[m].id < target) {l = m + 1;} else {// 若x小,则忽略右半部分r = m - 1;}}// 若未找到元素,返回-1return -1;
}void find_student_by_id()
{int id, ret;printf("Enter student ID to search: ");scanf("%d", &id);ret = binary_search(students, 0, student_count, id);if (ret != -1) {print_title();printf("%-4d %-10s %-.2f\n", students[ret].id, students[ret].name, students[ret].score);return;}printf("Student with ID %d not found!\n", id);
}void find_student_by_name()
{int i, is_find = 0;char name[MAX_NAME_LEN];printf("Enter student name to search: ");scanf("%s", name);for(i = 0; i < student_count; i++) {if(strcmp(students[i].name, name) == 0) {print_title();printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);is_find = 1;}}if (is_find == 0) {printf("Student with name %s not found!\n", name);}
}void add_score()
{int id, i;float score;printf("Enter student ID: ");scanf("%d", &id);printf("Enter student score: ");scanf("%f", &score);for(i = 0; i < student_count; i++) {if(students[i].id == id) {students[i].score = score;printf("Score added successfully!\n");return;}}printf("Student with ID %d not found!\n", id);
}void display_average_score()
{float total = 0.0;int i;for(i = 0; i < student_count; i++) {total += students[i].score;}printf("Average score of all students: %.2f\n", total / student_count);
}int init_student_info()
{if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在return 0;}FILE *fp = fopen(STUDENT_SYSTEM, "r");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}#define BUF_SIZE 1024char buf[BUF_SIZE];Student s;while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {sscanf(buf, "%d %s %f\n", &s.id, s.name, &s.score);update_student_info(s, FALSE);}fclose(fp);return 0;}void swap(Student *a, Student *b)
{Student tmp = *a;*a = *b;*b = tmp;
}void bubble_sort_by_score(Student *s, int n)
{int i, j;for (i = 0; i < n-1; i++) {for (j = 0; j < n-i-1; j++) { // 最后 i 个已经排序好了, 遍历未排序的部分if (s[j].score < s[j+1].score) {// 如果当前元素大于后面的元素,交换它们swap(&s[j], &s[j+1]);}}}
}int do_process(int choice)
{switch(choice) {case 0:printf("Exiting...\n");break;case 1:add_student();break;case 2:display_all_students();break;case 3:find_student_by_id();break;case 4:find_student_by_name();break;case 5:add_score();break;case 6:display_average_score();break;case 7:bubble_sort_by_score(students, student_count);display_all_students();break;default:printf("Invalid choice!\n");}return 0;
}int do_exit(int fd)
{int ret;char *exit_instruct = "Exit";ret = send(fd, exit_instruct, strlen(exit_instruct), 0);if (ret == -1) {perror("sent failed!\n");return -1;}printf("send: %s\n", exit_instruct);return 0;
}int do_add_student(int fd)
{int ret;char *enter_id_helps = "Enter student ID:";char *name_helps = "Enter student name:";Student s;char buf[BUF_SIZE];ret = send(fd, enter_id_helps, strlen(enter_id_helps), 0);if (ret == -1) {perror("sent failed!\n");return -1;}printf("send: %s\n", enter_id_helps);// Read data from the socketret = read(fd, buf, BUF_SIZE);if (ret == -1) {perror("read failed!\n");return -1;}s.id = atoi(buf);ret = send(fd, name_helps, strlen(name_helps), 0);if (ret == -1) {perror("sent failed!\n");return -1;}// Read data from the socketmemset(buf, 0, BUF_SIZE);ret = read(fd, buf, BUF_SIZE);if (ret == -1) {perror("read failed!\n");return -1;}strcpy(s.name, buf);s.score = 0.0; // 初始成绩设置为0update_student_info(s, TRUE);return 0;
}int server_process_to_client(int fd, char *buffer)
{int choice = atoi(buffer);switch(choice) {case 0:do_exit(fd);return 1;case 1:do_add_student(fd);break;default:printf("Invalid choice!\n");}return 0;
}void *do_data_process(void *arg)
{int ret;char buffer[BUF_SIZE] = {0};int conn_fd = *(int *)arg;while (1) {// Send data to the clientret = send(conn_fd, welcome_info, strlen(welcome_info), 0);if (ret == -1) {perror("sent failed!\n");break;}// Read data from the socketmemset(buffer, 0, BUF_SIZE);ret = read(conn_fd, buffer, BUF_SIZE);if (ret == -1) {perror("read failed!\n");break;}printf("recv: %s, %d\n", buffer, strlen(buffer));ret = server_process_to_client(conn_fd, buffer);if (ret == 1) {break;}}close(conn_fd);return NULL;
}int socket_server_init()
{int ret;int server_fd, conn_fd;int opt = 1;struct sockaddr_in address;int addrlen = sizeof(address);pthread_t thread;// 创建 TCP socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed!");exit(EXIT_FAILURE);}if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt!");exit(EXIT_FAILURE);}#define PORT 8080address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// Bind the socket to the addressif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed!");exit(EXIT_FAILURE);}// Listen for connectionsif (listen(server_fd, 3) < 0) {perror("listen!");exit(EXIT_FAILURE);}while (1) {// Accept a connectionif ((conn_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 启动线程去处理数据ret = pthread_create(&thread, NULL, do_data_process, &conn_fd);if (ret) {printf("pthread_create failed, ret:%d\n", ret);exit(EXIT_FAILURE);}}close(server_fd);return 0;
}void welcome_sys_menu()
{printf("%s", welcome_info);
}int main()
{int choice;int ret;students = stu_sys_init(MAX_STUDENTS);if (students == NULL) {printf("student system init failed, exit!\n");return -1;}ret = init_student_info();if (ret) {printf("init_student_info failed!\n");return 1;}display_all_students();socket_server_init();do {welcome_sys_menu();scanf("%d", &choice);do_process(choice);} while(choice != 0);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/706147.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言标准库函数qsort( )——数据排序

大家好&#xff01;我是保护小周ღ&#xff0c;本期为大家带来的是深度解剖C语言标准库函数 qsort()&#xff0c;qsort()函数他可以对任意类型的数据排序&#xff0c;博主会详细解释函数使用方法&#xff0c;以及使用快速排序的左右指针法模拟实现函数功能&#xff0c;这样的排…

IT廉连看——C语言——分支语句

IT廉连看—分支语句 一、什么是语句 C语句可分为以下五类&#xff1a; 表达式语句 函数调用语句 控制语句 复合语句 空语句 本周后面介绍的是控制语句。 控制语句用于控制程序的执行流程&#xff0c;以实现程序的各种结构方式&#xff0c;它们由特定的语句定义符组成&…

Delphi 报错 Type androidx.collection.ArraySet is defined multiple times

Delphi 11 建立一个新的 Multi-Device Application 编译成app的时候报错 报错信息 [PAClient Error] Error: E7688 Unable to execute "E:\Program\Java\jdk1.8.0_301\bin\java.exe" -cp "e:\program\embarcadero\studio\22.0\bin\Android\r8-3.3.28.jar"…

FPGA_SD卡读写

一 SD卡 SD卡&#xff0c;安全数字卡&#xff0c;体积小&#xff0c;容量大&#xff0c;存储速度块&#xff0c;支持热插拔。 二 SD卡存储容量 SD卡类型协议规范容量等级SDSCSD1.0上限至2GBSDHCSD2.02GB至32GBSDXCSD3.032GB至2TB 三 SD卡速度等级 标志串列数据写入速度UHS…

MWC 2024丨美格智能发布全新5G-A模组及FWA解决方案,将5.5G带入现实

2月26日&#xff0c;在MWC 2024世界移动通信大会上&#xff0c;美格智能正式宣布推出5G-A模组SRM817WE以及全新的5G-A FWA解决方案&#xff0c;包含5G-A CPE解决方案SRT858M、5G-A MiFi解决方案SRT878H和5G-A ODU解决方案SRT853MX&#xff0c;旨在进一步提升网络性能&#xff0…

跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture

封装2DRenderer&#xff1a; Renderer.h: #include"ytpch.h" #include"Renderer.h" #include <Platform/OpenGL/OpenGLShader.h> #include"Renderer2D.h" namespace YOTO {Renderer::SceneData* Renderer::m_SceneData new Renderer::S…

python中“全局变量”之谜

全局变量&#xff0c;是不是以为着在整个程序中的值都是一样的&#xff0c;是不是都是同一个呢&#xff1f; 我们通过下面的例子来看全局"变量之变” 上面的程序运行结果如下&#xff1a; 从上面的运行结果可以看出&#xff1a;尽管变量num被声明为全局变量&#xff0c;在…

测试基础2:接口测试入门儿 哟呼开心

单元测试&#xff1a;一段代码的功能是否正确&#xff0c;在软件开发中进行的测试活动&#xff1b; 单元测试框架&#xff1a; java&#xff1a;junit&#xff0c;testNG c#:NUint python&#xff1a;pytest、unittest接口测试&#xff1a;检测外部系统与系统之间以及内部各个子…

腾讯云4核8g云服务器能承受多少人访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

MFC web文件 CHttpFile的使用初探

MFC CHttpFile的使用 两种方式&#xff0c;第一种OpenURL&#xff0c;第二种SendRequest&#xff0c;以前捣鼓过&#xff0c;今天再次整结果发现各种踩坑&#xff0c;好记性不如烂笔头&#xff0c;记录下来。 OpenURL 这种方式简单粗暴&#xff0c;用着舒服。 try {//OpenU…

图形系统开发实战课程:进阶篇(上)——7.图形交互操作: 视点控制与动画

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形交互操作: 视点控制与动画”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-7.html 第七章 图形交互操作: 视点控制与…

[云原生] 二进制安装K8S(中)部署网络插件和DNS

书接上文&#xff0c;我们继续部署剩余的插件 一、K8s的CNI网络插件模式 2.1 k8s的三种网络模式 K8S 中 Pod 网络通信&#xff1a; &#xff08;1&#xff09;Pod 内容器与容器之间的通信 在同一个 Pod 内的容器&#xff08;Pod 内的容器是不会跨宿主机的&#xff09;共享…

c语言经典测试题4

1.题1 #include <stdio.h>//没有break的话&#xff0c;输入什么都会往下一直执行下去&#xff0c;而且default在最后就会全都执行 int main() {char c;int v0 0, v1 0, v2 0;do{switch (c getchar())// 输入ADescriptor{casea:caseA:casee:caseE:casei:caseI:caseo:…

【Python笔记-设计模式】责任链模式

一、说明 旨在将请求沿着处理者链进行发送。收到请求后&#xff0c;每个处理者均可对请求进行处理&#xff0c;或将其传递给链上的下个处理者。 (一) 解决问题 将请求的发送者和接受者解耦&#xff0c;并使请求随着处理对象链传递&#xff0c;优化系统内部处理逻辑 (二) 使…

【算法 - 动态规划】找零钱问题Ⅰ

在前面的动态规划系列文章中&#xff0c;关于如何对递归进行分析的四种基本模型都介绍完了&#xff0c;再来回顾一下&#xff1a; 从左到右模型 &#xff1a;arr[index ...] 从 index 之前的不用考虑&#xff0c;只考虑后面的该如何选择 。范围尝试模型 &#xff1a;思考 [L ,…

【BUG 记录】MyBatis-Plus 处理枚举字段和 JSON 字段

【BUG 记录】MyBatis-Plus 处理枚举字段和JSON字段 一、枚举字段&#xff08;mysql环境已测、postgresql环境已测&#xff09;1.1 场景1.2 定义枚举常量1.3 配置枚举处理器1.4 测试 二、JSON字段&#xff08;mysql环境已测&#xff09;2.1 导包2.2 使用对象接受2.3 测试 三、JS…

图片录入设备、方式与质量对图片转Excel的影响

随着数字化时代的到来&#xff0c;图片已经成为人们日常生活中不可或缺的一部分。在各行各业中&#xff0c;图片的应用越发广泛&#xff0c;从而促使了图片处理技术的快速发展。然而&#xff0c;图片的质量对于后续数据处理和分析的准确性和可靠性有着至关重要的影响。本文将从…

【k8s配置与存储--持久化存储(PV、PVC、存储类)】

1、PV与PVC 介绍 持久卷&#xff08;PersistentVolume&#xff0c;PV&#xff09; 是集群中的一块存储&#xff0c;可以由管理员事先制备&#xff0c; 或者使用存储类&#xff08;Storage Class&#xff09;来动态制备。 持久卷是集群资源&#xff0c;就像节点也是集群资源一样…

年龄性别预测3:Android实现年龄性别预测和识别(含源码,可实时预测)

年龄性别预测3&#xff1a;Android实现年龄性别预测和识别(含源码&#xff0c;可实时预测) 目录 年龄性别预测3&#xff1a;Android实现年龄性别预测和识别(含源码&#xff0c;可实时预测) 1.年龄性别预测和识别方法 2.人脸检测方法 3.年龄性别预测和识别模型训练 &#…

【Golang】Golang使用embed加载、打包静态资源文件

【Golang】Golang使用embed加载、打包静态资源文件 大家好 我是寸铁&#x1f44a; 总结了一篇Golang使用embed加载静态资源文件的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 事情是这样的&#xff1a;前不久&#xff0c;有同学问我,golang怎么把静态资源文件打包成一…