1.config tab-4
vi /etc/virc或者
1.配置文件中如果要添加注释,不能用#,要使用”
2.u命令回退上次的操作
3.复制不带行号,在/etc/virc的末尾添加se mouse+=a
" add tab space
set 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.h
4 directories, 9 files
2.cat makefile
#gcc ./main/main.c ./server/server.c ./client/client.c -o ipc
#只写这一行应该写在shell里而不是makefile
all: ipc
ipc: 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 ipc
3.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;
}
// ... 后续代码 ...
}