You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言Shared Memory客户端服务端不同步及矩阵转置实现求助

基于共享内存的C语言客户端服务端通信问题

用C语言实现共享内存客户端服务端程序时,遇到两个核心问题:

  1. 客户端与服务端无法同时运行,一方启动后另一方会直接退出;
  2. 首次运行时数据传输不符合预期,无法完成矩阵的发送-转置-回传流程。

预期功能:客户端输入矩阵后传给服务端,服务端显示原矩阵并计算转置,再将转置矩阵回传给客户端显示。


需求说明

  1. 客户端接收Matrix并传输至服务端;
  2. 服务端显示接收的Matrix并计算其转置;
  3. 服务端将转置后的Matrix回传给客户端;
  4. 客户端显示接收的转置Matrix。

原client.c代码

/* 编写基于Shared Memory的客户端服务端程序,实现数据传输:客户端接收Matrix并传输至服务端,服务端显示接收的Matrix并计算其转置,再将转置后的Matrix回传给客户端,客户端显示接收的转置Matrix。 */

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SIZE 3
int main()
{

    struct matrix{
        int arr[SIZE][SIZE];
        int transpose[SIZE][SIZE];
        int r,c;
    }buf;
    
    struct matrix* ptr;
    int shmid, pid;
    key_t key = ftok("shmfile",65);
  
   // shmget返回标识符存入shmid
   shmid = shmget(key,1024,0666|IPC_CREAT);
  
   // shmat连接至共享内存
   ptr = (struct matrix*) shmat(shmid,(struct matrix*)0,0);
  
   printf("请输入数据 --\n");
   for(int i=0;i<3;i++){
    for(int j=0;j<3;j++){
        int temp;
        scanf("%d",&temp);
        ptr->arr[i][j] = temp;
    }
   }
  
   printf("内存中写入的数据:\n");

   for(int i=0;i<3;i++)
   {
    printf("\n");
    for(int j=0;j<3;j++)
    {
        printf("%d ",ptr->transpose[i][j]);
    }
   }
   printf("\n");
   return 0;
}

原server.c代码

/* 编写基于Shared Memory的客户端服务端程序,实现数据传输:客户端接收Matrix并传输至服务端,服务端显示接收的Matrix并计算其转置,再将转置后的Matrix回传给客户端,客户端显示接收的转置Matrix。 */

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SIZE 3
  
int main()
{

    struct matrix{
        int arr[SIZE][SIZE];
        int transpose[SIZE][SIZE];
        int r,c;
    }buf;
    
    struct matrix* ptr;
    int shmid, pid;
   key_t key = ftok("shmfile",65);
  
   // shmget返回标识符存入shmid
   shmid = shmget(key,1024,0666|IPC_CREAT);
  
   // shmat连接至共享内存
   ptr = (struct matrix*) shmat(shmid,(struct matrix*)0,0);
   printf("\n转置前");
   

// 打印原矩阵
   for(int i=0;i<3;i++)
   {
    printf("\n");
    for(int j=0;j<3;j++)
    {
        printf("%d ",ptr->arr[i][j]);
    }
   }
   printf("\n");


for (int i = 0; i < 3; ++i)
  for (int j = 0; j < 3; ++j) {
    ptr->transpose[j][i] = ptr->arr[i][j];
  }
      
   printf("转置矩阵已写入内存:\n");
   
     
    return 0;
}

原运行输出

服务端首次运行

sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ gcc q1server.c -o q1server
sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ ./q1server

转置前
0 0 0
0 0 0
0 0 0
转置矩阵已写入内存:

客户端首次运行

sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ gcc q1client.c -o q1client
sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ ./q1client
请输入数据 --
1
2
3
4
5
6
7
8
9
内存中写入的数据:

0 0 0
0 0 0
0 0 0

再次运行服务端

sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ ./q1server

转置前
1 2 3
4 5 6
7 8 9
转置矩阵已写入内存:

再次运行客户端

sharon@LAPTOP-5LEVPDNC:~/CN_LAB/L5$ ./q1client
请输入数据 --
1
2
3
4
5
6
7
8
9
内存中写入的数据:

1 4 7
2 5 8
3 6 9

问题根源

  1. 缺乏进程同步机制:共享内存仅提供内存空间共享,不保证进程间的读写顺序。当前代码启动后直接完成读写就退出,导致双方无法同时运行,也无法确保数据写入后再被读取、处理完成后再被回读。
  2. 读写时机不匹配:客户端写入矩阵后立即读取转置矩阵,但此时服务端尚未处理;服务端启动时直接读取矩阵,此时客户端可能还未完成输入,因此首次运行读到初始值0。

修复方案

使用System V信号量实现进程间同步,配合共享内存完成有序的读写流程,同时优化共享内存的创建与使用:

步骤1:确保shmfile存在

先执行命令创建文件:

touch shmfile

修复后的client.c

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3

// 信号量操作联合体
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

struct matrix{
    int arr[SIZE][SIZE];
    int transpose[SIZE][SIZE];
    int status; // 0:未写入, 1:已写入等待处理, 2:处理完成可读取
};

int main()
{
    struct matrix* ptr;
    int shmid, semid;
    key_t key = ftok("shmfile",65);
  
    // 创建/获取共享内存,使用结构体大小指定内存大小
    shmid = shmget(key, sizeof(struct matrix), 0666|IPC_CREAT);
    if(shmid == -1){
        perror("shmget failed");
        return 1;
    }
  
    // 连接共享内存
    ptr = (struct matrix*) shmat(shmid, NULL, 0);
    if(ptr == (void*)-1){
        perror("shmat failed");
        return 1;
    }

    // 创建/获取信号量,2个信号量:0用于客户端通知服务端,1用于服务端通知客户端
    semid = semget(key, 2, 0666|IPC_CREAT);
    if(semid == -1){
        perror("semget failed");
        shmdt(ptr);
        return 1;
    }

    // 初始化信号量:客户端信号量(0)初始为0,服务端信号量(1)初始为0
    union semun sem_init;
    sem_init.val = 0;
    semctl(semid, 0, SETVAL, sem_init);
    semctl(semid, 1, SETVAL, sem_init);
  
    printf("请输入3x3矩阵数据 --\n");
    for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
            scanf("%d", &ptr->arr[i][j]);
        }
    }
    ptr->status = 1; // 标记矩阵已写入

    // 发送信号通知服务端可以处理
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = 1; // V操作,增加信号量
    sem_op.sem_flg = 0;
    semop(semid, &sem_op, 1);

    // 等待服务端处理完成的信号
    sem_op.sem_num = 1;
    sem_op.sem_op = -1; // P操作,等待信号量>0
    semop(semid, &sem_op, 1);

    // 读取并显示转置矩阵
    printf("收到服务端返回的转置矩阵:\n");
    for(int i=0;i<SIZE;i++){
        printf("\n");
        for(int j=0;j<SIZE;j++){
            printf("%d ", ptr->transpose[i][j]);
        }
    }
    printf("\n");

    // 断开共享内存连接
    shmdt(ptr);
    return 0;
}

修复后的server.c

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3

// 信号量操作联合体
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

struct matrix{
    int arr[SIZE][SIZE];
    int transpose[SIZE][SIZE];
    int status; // 0:未写入, 1:已写入等待处理, 2:处理完成可读取
};

int main()
{
    struct matrix* ptr;
    int shmid, semid;
    key_t key = ftok("shmfile",65);
  
    // 获取共享内存
    shmid = shmget(key, sizeof(struct matrix), 0666|IPC_CREAT);
    if(shmid == -1){
        perror("shmget failed");
        return 1;
    }
  
    // 连接共享内存
    ptr = (struct matrix*) shmat(shmid, NULL, 0);
    if(ptr == (void*)-1){
        perror("shmat failed");
        return 1;
    }

    // 获取信号量
    semid = semget(key, 2, 0666|IPC_CREAT);
    if(semid == -1){
        perror("semget failed");
        shmdt(ptr);
        return 1;
    }

    // 等待客户端写入完成的信号
    struct sembuf sem_op;
    sem_op.sem_num = 0;
    sem_op.sem_op = -1; // P操作
    semop(semid, &sem_op, 1);

    // 显示原矩阵
    printf("收到客户端的矩阵:\n");
    for(int i=0;i<SIZE;i++){
        printf("\n");
        for(int j=0;j<SIZE;j++){
            printf("%d ", ptr->arr[i][j]);
        }
    }
    printf("\n");

    // 计算转置矩阵
    for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
            ptr->transpose[j][i] = ptr->arr[i][j];
        }
    }
    ptr->status = 2; // 标记转置完成

    // 发送信号通知客户端可以读取
    sem_op.sem_num = 1;
    sem_op.sem_op = 1; // V操作
    semop(semid, &sem_op, 1);

    printf("转置矩阵已写入共享内存\n");

    // 断开共享内存连接
    shmdt(ptr);
    return 0;
}

运行方法

  1. 先启动服务端(会阻塞等待客户端信号):
gcc server.c -o server
./server
  1. 再打开另一个终端运行客户端,输入矩阵数据:
gcc client.c -o client
./client

额外注意事项

  • 若不再使用共享内存和信号量,可手动删除:
# 查看共享内存和信号量
ipcs -m
ipcs -s
# 删除指定的共享内存(shmid为对应ID)
ipcrm shm <shmid>
# 删除指定的信号量(semid为对应ID)
ipcrm sem <semid>

内容的提问来源于stack exchange,提问作者potato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 15:40:21