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
?命令逐個終止進程:
牛客網刷題