五一假期作业

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]++;              // 对应字符计数+1
        pthread_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

手动终止进程

  1. 查找进程ID

    在终端中执行以下命令,找到相关进程的PID:

    复制代码
    ps aux | grep -E 'main_process|sub_process|monitor'
  2. 终止进程

    使用 kill 命令逐个终止进程:

牛客网刷题

相关推荐
Sheep Shaun7 分钟前
C++类与对象—下:夯实面向对象编程的阶梯
c语言·开发语言·数据结构·c++·算法
yi个名字1 小时前
链表高级操作与算法
数据结构·算法·链表
wuqingshun3141591 小时前
蓝桥杯 19. 植树
c++·算法·蓝桥杯·深度优先·动态规划
王禄DUT2 小时前
网络延时 第四次CCF-CSP计算机软件能力认证
c++·算法
福居路冥想的草莓2 小时前
矩阵置零(中等)
数据结构·算法·矩阵
方方土3333 小时前
ABC 404
数据结构·算法·图论
wang__123003 小时前
力扣119题解
算法·leetcode·职场和发展
I AM_SUN3 小时前
42. 接雨水(相向双指针/前后缀分解),一篇文章讲透彻
c++·算法·leetcode
csdn_aspnet6 小时前
C# 检查某个点是否存在于圆扇区内(Check whether a point exists in circle sector or not)
算法·c#