五一假期作业
sub_process.c
#include <stdio.h> // 标准输入输出库
#include <pthread.h> // POSIX线程库
#include <sys/ipc.h> // IPC基础定义(如消息队列/共享内存)
#include <sys/msg.h> // 消息队列操作相关
#include <sys/shm.h> // 共享内存操作相关
#include <unistd.h> // 标准符号常量和类型
#include <string.h> // 字符串操作相关#define NUM_THREADS 4 // 定义线程数量为4
#define MAX_MSG_SIZE 1024 // 定义单条消息的最大长度// 消息队列数据结构
struct msg_buffer
{long msg_type; // 消息类型标识(必须非0)char msg_text[MAX_MSG_SIZE]; // 实际消息内容缓冲区
};// 共享内存数据结构
struct shm_data
{int char_count[256]; // ASCII字符频率统计数组(支持扩展ASCII)pthread_mutex_t lock; // 互斥锁保护共享数据
};int shmid; // 全局共享内存ID,供子进程或线程使用// 线程处理函数:负责从消息队列读取日志并统计字符
void* process_log(void* arg)
{int msgid = *(int*)arg; // 从参数获取消息队列ID(潜在问题:传递局部变量地址)struct msg_buffer msg; // 定义接收消息的临时缓冲区// 阻塞式接收消息队列中类型为1的消息ssize_t bytes_received = msgrcv(msgid, &msg, MAX_MSG_SIZE, 1, 0);if (bytes_received == -1){perror("msgrcv"); // 如果接收失败则打印错误信息return NULL;}// 将共享内存附加到当前进程的地址空间struct shm_data* shm = shmat(shmid, NULL, 0);if (shm == (void*)-1) {perror("shmat"); // 如果附加失败则打印错误信息return NULL;}// 遍历接收到的消息内容进行字符统计for (int i = 0; i < bytes_received; i++) { unsigned char c = msg.msg_text[i]; // 取当前字符(无符号避免负数索引)pthread_mutex_lock(&shm->lock); // 加锁保护共享数据shm->char_count[c]++; // 对应字符计数+1pthread_mutex_unlock(&shm->lock); // 解锁}shmdt(shm); // 分离共享内存(不影响其他进程/线程的挂接)return NULL;
}int main() {// 生成IPC对象唯一键值(基于文件路径和项目ID)key_t key = ftok("/tmp/logfile", 65);if (key == -1){perror("ftok"); // 如果生成失败则退出程序return 1;}// 创建消息队列(权限0666,若不存在则创建)int msgid = msgget(key, 0666 | IPC_CREAT);if (msgid == -1) {perror("msgget"); // 如果获取失败则退出程序return 1;}// 创建共享内存段(大小为shm_data结构体,权限0666,若不存在则创建)shmid = shmget(key, sizeof(struct shm_data), 0666 | IPC_CREAT);if (shmid == -1){perror("shmget"); // 如果创建失败则退出程序return 1;}// 将共享内存附加到当前进程地址空间并进行初始化struct shm_data* shm = shmat(shmid, NULL, 0);memset(shm, 0, sizeof(struct shm_data)); // 清空共享内存内容pthread_mutex_init(&shm->lock, NULL); // 初始化互斥锁// 创建线程池(NUM_THREADS个线程)pthread_t threads[NUM_THREADS];for (int i = 0; i < NUM_THREADS; i++) {// 创建线程并传递消息队列ID指针(潜在问题:msgid是栈变量)if (pthread_create(&threads[i], NULL, process_log, &msgid) != 0){perror("pthread_create"); // 如果线程创建失败则退出程序return 1;}}// 等待所有线程执行完毕for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}// 分离共享内存(主进程不再需要访问)shmdt(shm);return 0;
}
main_process.c
#include <stdio.h> // 标准输入输出库
#include <sys/ipc.h> // IPC基础定义(消息队列/共享内存等)
#include <sys/shm.h> // 共享内存操作相关函数
#include <pthread.h> // POSIX线程库
#include <unistd.h> // 标准符号常量和类型// 共享内存结构体(与子进程保持一致)
struct shm_data
{int char_count[256]; // ASCII字符频率统计数组(支持扩展ASCII)pthread_mutex_t lock; // 互斥锁保护共享数据
};int main()
{// 生成唯一键值(基于文件路径和项目ID)key_t key = ftok("/tmp/logfile", 65);if (key == -1){perror("ftok"); // 如果生成键值失败则退出程序return 1;}// 创建或获取共享内存段(大小为shm_data结构体)int shmid = shmget(key, sizeof(struct shm_data), 0666 | IPC_CREAT);if (shmid == -1) {perror("shmget"); // 如果获取共享内存失败则退出程序return 1;}// 将共享内存映射到当前进程地址空间struct shm_data* shm = shmat(shmid, NULL, 0);if (shm == (void*)-1) {perror("shmat"); // 如果映射失败则退出程序return 1;}// 实时监控循环(永久运行直到程序被强制终止)while (1) {sleep(1); // 每隔1秒更新一次统计信息// 加锁以保护共享数据pthread_mutex_lock(&shm->lock);printf("===== 字符统计 =====
");// 遍历所有可能的ASCII字符for (int i = 0; i < 256; i++) {if (shm->char_count[i] > 0) // 仅显示出现过的字符{if (i == ' ') {printf("空格: %d
", shm->char_count[i]); // 特殊处理空格字符} else {printf("%c: %d
", (char)i, shm->char_count[i]); // 显示可打印字符}}}// 解锁以允许其他线程访问pthread_mutex_unlock(&shm->lock);}// 分离共享内存(实际上不会执行到这里)shmdt(shm);return 0;
}
monitor.c
#include <stdio.h> // 标准输入输出库
#include <sys/ipc.h> // IPC基础定义(消息队列/共享内存等)
#include <sys/shm.h> // 共享内存操作相关函数
#include <pthread.h> // POSIX线程库
#include <unistd.h> // 标准符号常量和类型// 共享内存结构体(与子进程保持一致)
struct shm_data
{int char_count[256]; // ASCII字符频率统计数组(支持扩展ASCII)pthread_mutex_t lock; // 互斥锁保护共享数据
};int main()
{// 生成唯一键值(基于文件路径和项目ID)key_t key = ftok("/tmp/logfile", 65);if (key == -1){perror("ftok"); // 如果生成键值失败则退出程序return 1;}// 创建或获取共享内存段(大小为shm_data结构体)int shmid = shmget(key, sizeof(struct shm_data), 0666 | IPC_CREAT);if (shmid == -1) {perror("shmget"); // 如果获取共享内存失败则退出程序return 1;}// 将共享内存映射到当前进程地址空间struct shm_data* shm = shmat(shmid, NULL, 0);if (shm == (void*)-1) {perror("shmat"); // 如果映射失败则退出程序return 1;}// 实时监控循环(永久运行直到程序被强制终止)while (1) {sleep(1); // 每隔1秒更新一次统计信息// 加锁以保护共享数据pthread_mutex_lock(&shm->lock);printf("===== 字符统计 =====
");// 遍历所有可能的ASCII字符for (int i = 0; i < 256; i++) {if (shm->char_count[i] > 0) // 仅显示出现过的字符{if (i == ' ') {printf("空格: %d
", shm->char_count[i]); // 特殊处理空格字符} else {printf("%c: %d
", (char)i, shm->char_count[i]); // 显示可打印字符}}}// 解锁以允许其他线程访问pthread_mutex_unlock(&shm->lock);}// 分离共享内存(实际上不会执行到这里)shmdt(shm);return 0;
}
编译和运行 # 创建共享内存键值文件 touch /tmp/logfile# 编译代码 gcc main_process.c -o main_process gcc sub_process.c -o sub_process -lpthread gcc monitor.c -o monitor -lpthread# 生成测试日志 base64 /dev/urandom | head -n 1000 > test.log# 按顺序启动进程 ./sub_process & ./monitor & ./main_process
手动终止进程
-
查找进程ID
在终端中执行以下命令,找到相关进程的PID:ps aux | grep -E 'main_process|sub_process|monitor'
-
终止进程
使用kill
命令逐个终止进程:
牛客网刷题