1.config tab-4
vi /etc/virc或者
1.配置文件中如果要添加注释,不能用#,要使用”
2.u命令回退上次的操作
3.复制不带行号,在/etc/virc的末尾添加se mouse+=a
" add tab spaceset ts=4 "只设置这个就能把tab缩进为4,加上下面的tab直接被替换成4个空格,不是tab了,make出错"set softtabstop=4
"set shiftwidth=4
"set expandtab
"set autoindent" 显示行号,但是也会复制到行号,直接注释
"set nu
2.tree and makefile
1.tree ipc/
ipc/
├── clean.sh
├── client
│ ├── client.c
│ └── client.h
├── include
│ └── global_api.h
├── ipc
├── main
│ └── main.c
├── makefile
└── server├── server.c└── server.h4 directories, 9 files2.cat makefile
#gcc ./main/main.c ./server/server.c ./client/client.c -o ipc
#只写这一行应该写在shell里而不是makefile
all: ipcipc: main/main.c server/server.c client/client.c #加不加./都一样gcc -o ipc main/main.c server/server.c client/client.c # -o 在哪里都一样clean:rm -rf ipc3.cat clean.sh
make clean
3.注意事项:shm族函数并没有信号的通知机制,需要我们继续使用sem族函数
增加通知机制
server.c
cat server/server.c
#include "../include/global_api.h"void server_init(){/*key_t key = ftok(".", 1); //使用绝对路径比较合适if(key < 0){printf("\nftok err.\n");}*/int shmid = shmget(IPC_KEY, sizeof(int), IPC_CREAT | 0664);//0666);if (shmid == -1) { perror("shmget failed"); exit(1); }char* shared_mem = (char*)shmat(shmid, NULL, 0);if(shared_mem == (void*)-1){perror("shmat failed");}struct sembuf op; int semid = semget(IPC_KEY, 1, IPC_CREAT | 0664);/*union semun arg; //gcc 可能不支持,先注释掉arg.val = 0; if (semctl(semid, 0, SETVAL, arg) == -1) { perror("semctl SETVAL"); exit(1); }*/ while(1){sleep(1);op.sem_num = 0; // 信号量在信号量集中的索引op.sem_op = -1; //阻塞等待通知的到来op.sem_flg = 0; // 表示这是一次常规的操作if (semop(semid, &op, 1) == -1) {perror("semop");exit(1);}printf("i got it, shard_mem:[%s]\n", shared_mem);//[%c]\n", shared_mem);}
}
client.c
cat client/client.c
#include "../include/global_api.h"void client_init(){int shmid = shmget(IPC_KEY, sizeof(int), IPC_CREAT);// | 0666); if (shmid == -1) { perror("shmget failed"); exit(1); }char* shared_mem = (char*)shmat(shmid, NULL, 0);if(shared_mem == (void*)-1){perror("shmat failed");}struct sembuf op; // 获取信号量集 int semid = semget(IPC_KEY, 1, 0); if (semid == -1) { perror("semget"); exit(1); } *shared_mem = 'a' - 1; while(1){sleep(1);*shared_mem += 1;op.sem_num = 0; // 信号量在信号量集中的索引op.sem_op = 1; // 通知op.sem_flg = 0; //表示这是一次常规的操作if (semop(semid, &op, 1) == -1) {perror("semop");exit(1);}printf("\nclient modify the char.\n");}
}
4.how to make the shared_mem to complete IPC(没有增加通知,只需要把上面3的code替换下来即可)
main.c
cat main/main.c
#include "../include/global_api.h"int main(){pid_t server_pid = fork();if(server_pid < 0){printf("\nfork err\n");}else if(server_pid == 0){printf("\nfork server success.\n");server_init();}pid_t client_pid = fork();if(client_pid < 0){printf("\nfork err\n");}else if(client_pid == 0){printf("\nfork client success.\n");client_init();}else{int state;waitpid(server_pid, &state, 0);waitpid(client_pid, &state, 0);}return 0;
}
waitpid(server_pid, &state, 0); && waitpid(client_pid, &state, 0);是必须的,不然main进程直接返回了
server.c:server不用ftok生成唯一的key,直接在global_api.h里大家使用相同的IPC_KEY即可,shmget的第二个参数是共享内存的大小:
或者用一个更好的方法生成KEY:
// 使用ftok生成一个唯一的键 key = ftok("/tmp", 'R'); if (key == (key_t)-1) { perror("ftok"); exit(1); }
cat server/server.c
#include "../include/global_api.h"void server_init(){/*key_t key = ftok(".", 1);if(key < 0){printf("\nftok err.\n");}*/int shmid = shmget(IPC_KEY, sizeof(int), IPC_CREAT | 0664);//0666)i;if (shmid == -1) { perror("shmget failed"); exit(1); }char* shared_mem = (char*)shmat(shmid, NULL, 0);if(shared_mem == (void*)-1){perror("shmat failed");}while(1){sleep(1);printf("shard_mem:[%s]\n", shared_mem);//[%c]\n", shared_mem);}
}
server.h
cat server/server.h
void server_init();
client.c:client不用0664,因为server已经创建了共享空间的空间号,我们只需要加入即可
cat client/client.c
#include "../include/global_api.h"void client_init(){int shmid = shmget(IPC_KEY, sizeof(int), IPC_CREAT);// | 0666); if (shmid == -1) { perror("shmget failed"); exit(1); }char* shared_mem = (char*)shmat(shmid, NULL, 0);if(shared_mem == (void*)-1){perror("shmat failed");} shared_mem[0] = 'a'; //or *shared_mem = 'a';while(1){sleep(1);*shared_mem += 1;printf("\nclient modify the char\n");}
}
client.h
cat client/client.h
void client_init();
golbal_api.h
cat include/global_api.h
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/wait.h>#include "../client/client.h"
#include "../server/server.h"#define IPC_KEY 1234
5.other code
dd if=/dev/zero of=/tmp/shared_memory bs=1M count=1这条命令在Linux或Unix系统中用于通过dd(data duplicator)工具创建一个特定大小的文件。具体来说:if=/dev/zero:指定输入文件为/dev/zero,这是一个特殊的设备文件,它提供无限的零字节(\0)。
of=/tmp/shared_memory:指定输出文件为/tmp/shared_memory。这意味着从输入文件(/dev/zero)读取的数据将被写入到这个文件中。
bs=1M:设置块大小为1兆字节(1MB)。这意味着每次从输入文件读取和写入输出文件的数据块大小是1MB。
count=1:指定从输入文件读取并写入输出文件的数据块数量为1。
综合起来,这条命令将创建一个大小为1MB的文件/tmp/shared_memory,文件内容全部为零字节。这样的文件常用于需要预定大小空白文件的场合,例如作为共享内存区域的占位符。进程A:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h> int main() { int *flag_ptr; int fd = open("/tmp/shared_memory", O_RDWR | O_CREAT, 0666); if (fd == -1) { perror("open"); exit(1); } // 将文件大小设置为足够大的值以容纳我们的int if (ftruncate(fd, sizeof(int)) == -1) { perror("ftruncate"); exit(1); } // 映射文件到内存中 flag_ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (flag_ptr == MAP_FAILED) { perror("mmap"); exit(1); } // 写入flag *flag_ptr = 1; // 等待其他进程或进行其他操作... // 清理 munmap(flag_ptr, sizeof(int)); close(fd); return 0;
}进程B:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h> int main() { int *flag_ptr; int fd = open("/tmp/shared_memory", O_RDWR); if (fd == -1) { perror("open"); exit(1); } // 映射文件到内存中 flag_ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (flag_ptr == MAP_FAILED) { perror("mmap"); exit(1); } // 读取flag int flag = *flag_ptr; printf("Read flag: %d\n", flag); // ... 进行其他操作 ... // 清理 munmap(flag_ptr, sizeof(int)); close(fd); return 0;
}
匿名mmap:其实就是加了标志位,即MAP_SHARED
和MAP_ANONYMOUS
(或MAP_ANON
),并且把使用的fd直接变成-1
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h> int main() { // 映射区域的大小,例如4个字节 size_t size = 4; // 创建匿名映射区域 int *shared_memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (shared_memory == MAP_FAILED) { perror("mmap failed"); return 1; } // ... 后续代码 ...
}