甘肅住房建設(shè)廳的網(wǎng)站評論優(yōu)化
共享內(nèi)存
OVERVIEW
- 共享內(nèi)存
- 一、文件上鎖flock
- 二、共享內(nèi)存
- 1.關(guān)聯(lián)共享內(nèi)存ftok
- 2.獲取共享內(nèi)存shmget
- 3.綁定共享內(nèi)存shmat
- 4.綁定分離shmdt
- 5.控制共享內(nèi)存shmctl
- 三、親緣進(jìn)程間通信
- 1.共享內(nèi)存寫入與讀取
- 2.共享內(nèi)存解綁與刪除
- 3.共享內(nèi)存綜合
- 四、非親緣進(jìn)程間通信
- 1.通過sleep同步
- 2.通過條件變量同步
一、文件上鎖flock
可以利用flock系統(tǒng)調(diào)用實(shí)現(xiàn),當(dāng)有一個進(jìn)程在文件中進(jìn)程寫入操作時,其他進(jìn)程無法在該文件中進(jìn)行寫操作(只能進(jìn)行讀操作)。
- 多進(jìn)程實(shí)現(xiàn)前n項(xiàng)數(shù)求和(利用flock實(shí)現(xiàn))
#include "head.h"struct data {int now;//中間結(jié)果int sum;//求和結(jié)果
};void getnum(struct data *d) {int fd;if ((fd = open(".data", O_RDONLY)) < 0) {perror("setopen");exit(1);}read(fd, (void *)d, sizeof(struct data));close(fd);
}void setnum(struct data *d) {int fd;if ((fd = open(".data", O_RDWR | O_CREAT, 0600)) < 0) {//只有文件的所屬用戶(當(dāng)前的進(jìn)程)有訪問以及寫的權(quán)限perror("getopen");exit(1);}write(fd, (void *)d, sizeof(struct data));close(fd);
}void doSum(struct data *d, int max, int i) {int fd_lock;//將lock標(biāo)志給到某個文件上(.lock) 通過該文件判斷進(jìn)程是否有資格打開另一個被保護(hù)的文件(.data)if ((fd_lock = open(".lock", O_RDONLY)) < 0) {perror("lockopen");exit(1);}while (1) {//計(jì)算的過程需要上鎖flock(fd_lock, LOCK_EX);//加鎖(加鎖后其他進(jìn)程后面計(jì)算的語句將無法執(zhí)行)getnum(d);//從.data取出上個結(jié)果if (d->now >= max) break;//判斷 計(jì)算結(jié)果d->now++;d->sum += d->now;setnum(d);//將計(jì)算的結(jié)果放回.dataprintf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);flock(fd_lock, LOCK_UN);//為解鎖}close(fd_lock);
}int main(int argc, char *argv[]) {//多進(jìn)程實(shí)現(xiàn)求前n項(xiàng)和 同一時刻只有一個進(jìn)程持有該文件//計(jì)算從0到n的和 m個進(jìn)程//a.out -i -n nint opt;int ins = 1, max = 100;struct data d;d.now = 0;d.sum = 0;setnum(&d);while ((opt = getopt(argc, argv, "i:n:")) != -1) {switch (opt) {case 'i':ins = atoi(optarg);break;case 'n':max = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);exit(1);}}int i;pid_t pid;for (i = 0; i < ins; ++i) {//創(chuàng)建ins個進(jìn)程對文件進(jìn)行doSum操作if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;}if (pid == 0) {doSum(&d, max, i);} else {for (int k = 0; k < ins; ++k) wait(NULL);}return 0;
}
二、共享內(nèi)存
允許兩個或多個進(jìn)程共享一個給定的存儲區(qū),由于無需復(fù)制數(shù)據(jù),這是最快的IPC進(jìn)程間通信。
1.關(guān)聯(lián)共享內(nèi)存ftok
#include "head.h"int main() {//ftok將projectId與文件名字轉(zhuǎn)換為鍵值對key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);printf("123 = 0x%x\n", 123);return 0;
}
2.獲取共享內(nèi)存shmget
#include "head.h"int main() {//1.申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);return 0;
}
3.綁定共享內(nèi)存shmat
#include "head.h"int main() {//1.申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}sleep(10);return 0;
}
4.綁定分離shmdt
#include "head.h"int main() {//1.申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}//4.將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}return 0;
}
5.控制共享內(nèi)存shmctl
#include "head.h"int main() {//1.申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值key_t key;if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}printf("key = 0x%x\n", key);//2.根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符int shmid;if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}printf("shmid = %d\n", shmid);//3.將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)void *shmemory = NULL;if ((shmemory = shmat(shmid, NULL, 0)) == (void*)-1) {perror("shmat");exit(1);}//4.將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}//5.shmctl刪除共享內(nèi)存空間if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {perror("shmctl");exit(1);}return 0;
}
三、親緣進(jìn)程間通信
1.共享內(nèi)存寫入與讀取
#include "head.h"//共享內(nèi)存綜合運(yùn)用
int main() {key_t key;int shmid;pid_t pid;char *shmemory = NULL;//1.開辟一塊共享內(nèi)存空間//(1)申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}//(2)根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}//(3)將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {perror("shmat");exit(1);}//2.創(chuàng)建子進(jìn)程 進(jìn)行運(yùn)算操作if ((pid = fork()) < 0) {perror("fork");exit(1);}if (pid) {//父進(jìn)程寫入while(1) {printf("i am the father : \n");scanf("%[^\n]s", shmemory);//向共享內(nèi)存中寫入getchar();//吞掉回車否則不停循環(huán)sleep(2);}} else {//子進(jìn)程讀出while (1) {sleep(1);if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);//如果共享內(nèi)存空間中有數(shù)據(jù)才進(jìn)行輸出memset(shmemory, 0, 4096);//臨時清空共享存儲空間}}return 0;
}
2.共享內(nèi)存解綁與刪除
#include "head.h"//共享內(nèi)存綜合運(yùn)用
int main() {key_t key;int shmid;pid_t pid;char *shmemory = NULL;//1.開辟一塊共享內(nèi)存空間//(1)申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值if ((key = ftok("1.ftok.c", 123)) < 0) {perror("ftok");exit(1);}//(2)根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) < 0) {perror("shmget");exit(1);}//(3)將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)if ((shmemory = shmat(shmid, NULL, 0)) == (void *)-1) {perror("shmat");exit(1);}//2.創(chuàng)建子進(jìn)程 利用shmdt實(shí)現(xiàn) 一次讀取一次讀入操作if ((pid = fork()) < 0) {perror("fork");exit(1);}if (pid) {printf("i am the father : \n");scanf("%[^\n]s", shmemory);getchar();} else {sleep(5);if (strlen(shmemory)) printf("i am the child : %s\n", shmemory);memset(shmemory, 0, 4096);}//3.刪除開辟的共享內(nèi)存空間//(1)將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)解除int flag;if ((flag = shmdt(shmemory)) < 0) {perror("shmdt");exit(1);}//(2)shmctl刪除共享內(nèi)存空間(父進(jìn)程執(zhí)行)if (pid) {wait(NULL);if ((flag = shmctl(shmid, IPC_RMID, NULL)) < 0) {perror("shmctl");exit(1);}}sleep(5);return 0;
}
3.共享內(nèi)存綜合
- 利用共享內(nèi)存實(shí)現(xiàn)多進(jìn)程前n項(xiàng)數(shù)求和(利用共享內(nèi)存實(shí)現(xiàn))
#include "head.h"struct data {int now;//中間結(jié)果int sum;//求和結(jié)果
};void doSum(struct data *d, int max, int i) {while (1) {//計(jì)算的過程需要上鎖if (d->now >= max) break;//判斷 計(jì)算結(jié)果d->now++;d->sum += d->now;printf("<i am the %dth child> now = %d, sum = %d\n", i, d->now, d->sum);}
}int main(int argc, char *argv[]) {//1.命令行解析 a.out -i -n nint opt;int ins = 1, max = 100;// struct data d;// d.now = 0;// d.sum = 0;// setnum(&d);while ((opt = getopt(argc, argv, "i:n:")) != -1) {switch (opt) {case 'i':ins = atoi(optarg);break;case 'n':max = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -i num1 -n num2", argv[0]);exit(1);}}//2.共享內(nèi)存的創(chuàng)建于綁定key_t key;int shmid;struct data *shmemory = NULL;//2.1申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值if ((key = ftok("5.shm_sum.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符if ((shmid = shmget(key, sizeof(struct data), IPC_CREAT | 0600)) < 0) {perror("shmget");exit(1);}//2.3將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)if ((shmemory = (struct data *)shmat(shmid, NULL, 0)) == (struct data *)-1) {perror("shmat");exit(1);}shmemory->now = 0;shmemory->sum = 0;//3.創(chuàng)建ins個子進(jìn)程對文件進(jìn)行doSum操作int i;pid_t pid;for (i = 0; i < ins; ++i) {if ((pid = fork()) < 0) {perror("fork()");exit(1);}if (pid == 0) break;}if (pid == 0) {doSum(shmemory, max, i);} else {for (int k = 0; k < ins; ++k) wait(NULL);printf("%d\n", shmemory->sum);}return 0;
}
成功輸出結(jié)果,前100項(xiàng)求和的結(jié)果為5050,但是當(dāng)使用程序求前10000項(xiàng)和時,卻會出現(xiàn)問題如圖結(jié)果為50007661(錯誤結(jié)果)。
出現(xiàn)問題的原因是:執(zhí)行中的進(jìn)程沒有保障,進(jìn)程之間發(fā)生競爭(同一時刻多個進(jìn)程對內(nèi)存進(jìn)行讀寫操作,發(fā)生在多核處理器)
可以利用條件變量實(shí)現(xiàn)線程同步機(jī)制(進(jìn)程同步),從而避免資源搶占競爭。
四、非親緣進(jìn)程間通信
共享內(nèi)存實(shí)現(xiàn)多進(jìn)程計(jì)算,
- 單核不考慮同步關(guān)系,可以正常實(shí)現(xiàn)
- 多核不考慮同步關(guān)系,無法正常實(shí)現(xiàn)
- 需要設(shè)置同步關(guān)系
- 利用條件變量實(shí)現(xiàn)進(jìn)程同步
非親緣進(jìn)程之間的通信,
1.通過sleep同步
- 使用共享內(nèi)存實(shí)現(xiàn)兩個非親緣關(guān)系進(jìn)程(1號進(jìn)程、2號進(jìn)程)進(jìn)行通話
- 1號進(jìn)程只輸出2號進(jìn)程在共享內(nèi)存中輸入的數(shù)據(jù)
- 2號進(jìn)程只輸出1號進(jìn)程在共享內(nèi)存中輸入的數(shù)據(jù)
- 同步(通過sleep實(shí)現(xiàn)同步)
#include "head.h"struct SHM {int flag;//SHM能否讀寫int type;//第幾個進(jìn)程char mesg[50];//輸入的信息
};int main(int argc, char *argv[]) {//1.命令行解析 ./a.out -t 1|2 -m messageint opt;int type;char mesg[50];struct SHM *temp;//用于臨時存放準(zhǔn)備寫入共享內(nèi)存的數(shù)據(jù)if (argc != 5) {fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);exit(1);}while ((opt = getopt(argc, argv, "t:m:")) != -1) {switch (opt) {case 't':type = atoi(optarg);break;case 'm':strcpy(mesg, optarg);break;default:fprintf(stderr, "Usage : %s -t 1|2 -m message\n", argv[0]);exit(1);}}/***存在問題*為什么直接在switch中使用 temp->type = atoi(optarg); 會出現(xiàn)segmentfault呢?*必須使用臨時變量 int type; 來轉(zhuǎn)接數(shù)據(jù)才不會報(bào)錯? */temp->type = type;strcpy(temp->mesg, mesg);//2.共享內(nèi)存的創(chuàng)建與綁定key_t key;int shmid;struct SHM *shmemory = NULL;//2.1申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值if ((key = ftok("1.shm_my.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {if (errno == EEXIST) {//處理重復(fù)創(chuàng)建共享內(nèi)存空間if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {perror("shmget1");exit(1);}printf("shmemory exist!");} else {perror("shmget2");exit(1);}}//2.3將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {perror("shmat");exit(1);}//3.實(shí)現(xiàn)非親緣進(jìn)程間通信shmemory->flag = 0;//初始狀態(tài)為允許寫入while (1) {if (!shmemory->flag) {printf("<Process%d> : i get shmemory\n", temp->type);sprintf(shmemory->mesg, "<Process%d> : <%s>", temp->type, temp->mesg);//向共享內(nèi)存中寫入內(nèi)容shmemory->flag = 1;sleep(1);} else {printf("%s\n", shmemory->mesg);//從共享內(nèi)存中讀取 并輸出內(nèi)容shmemory->flag = 0;}}return 0;
}
2.通過條件變量同步
思考:如何通過條件變量以及互斥鎖,通過共享內(nèi)存空間實(shí)現(xiàn)多進(jìn)程同步
- 一個進(jìn)程1號進(jìn)程,作為主要發(fā)送進(jìn)程
- 多個進(jìn)程,輸出1號進(jìn)程發(fā)送的數(shù)據(jù)
- 利用條件變量和互斥鎖實(shí)現(xiàn)同步
#include "head.h"struct SHM {int type;//第幾個進(jìn)程char mesg[50];//輸入的信息pthread_mutex_t mutex;//互斥鎖pthread_cond_t cond;//條件變量
};int main(int argc, char *argv[]) {//1.命令行解析 ./a.out -t 1|2int opt;int type;if (argc != 3) {fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);exit(1);}while ((opt = getopt(argc, argv, "t:")) != -1) {switch (opt) {case 't':type = atoi(optarg);break;default:fprintf(stderr, "Usage : %s -t 1|2\n", argv[0]);exit(1);}}//2.共享內(nèi)存的創(chuàng)建與綁定key_t key;int shmid;struct SHM *shmemory = NULL;//2.1申請一塊共享內(nèi)存 將projectId與文件名字轉(zhuǎn)換為 共享內(nèi)存鍵值if ((key = ftok("2.shm_cond.c", 123)) == -1) {perror("ftok");exit(1);}//2.2根據(jù)共享內(nèi)存對應(yīng)的key值 和內(nèi)存大小size 得到共享內(nèi)存的標(biāo)識符if ((shmid = shmget(key, sizeof(struct SHM), IPC_CREAT | IPC_EXCL | 0600)) < 0) {if (errno == EEXIST) {//處理重復(fù)創(chuàng)建共享內(nèi)存空間if ((shmid = shmget(key, sizeof(struct SHM), 0600)) < 0) {perror("shmget1");exit(1);}printf("shmemory exist!\n");} else {perror("shmget2");exit(1);}}//2.3將進(jìn)程的動態(tài)內(nèi)存空間和 共享內(nèi)存空間關(guān)聯(lián)if ((shmemory = (struct SHM *)shmat(shmid, NULL, 0)) == (struct SHM *)-1) {perror("shmat");exit(1);}//3.實(shí)現(xiàn)非親緣進(jìn)程間通信if (type == 1) {//讓1號進(jìn)程初始化互斥鎖和信號量 并設(shè)為共享pthread_mutexattr_t mutex;pthread_condattr_t cond;pthread_mutexattr_init(&mutex);pthread_condattr_init(&cond);pthread_mutexattr_setpshared(&mutex, 1);//設(shè)置為共享pthread_condattr_setpshared(&cond, 1);//設(shè)置為共享pthread_mutex_init(&shmemory->mutex, &mutex);//初始化鎖pthread_cond_init(&shmemory->cond, &cond);//初始化條件}if (type == 1) {while (1) {printf("ok\n");scanf("%[^\n]s", shmemory->mesg); getchar();if (strlen(shmemory->mesg)) pthread_cond_signal(&shmemory->cond);//1號進(jìn)程寫入后通知其他進(jìn)程}} else {while (1) {pthread_mutex_lock(&shmemory->mutex);//一旦有某個進(jìn)程拿到了共享內(nèi)存 則將共享內(nèi)存上鎖pthread_cond_wait(&shmemory->cond, &shmemory->mutex);//共享內(nèi)存上鎖后 等待1號進(jìn)程寫入完成的通知//if (strlen(shmemory->mesg)) printf("<Process%d> : %s\n", type, shmemory->mesg);//將共享內(nèi)存中寫入的數(shù)據(jù)輸出memset(shmemory->mesg, 0, strlen(shmemory->mesg));//清空共享內(nèi)存pthread_mutex_unlock(&shmemory->mutex);}}return 0;
}