日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
冷門知識(shí)點(diǎn):進(jìn)程間通信如何加鎖?

關(guān)于進(jìn)程間的通信方式估計(jì)大多數(shù)人都知道,這也是常見的面試八股文之一。

個(gè)人認(rèn)為這種面試題沒什么意義,無非就是答幾個(gè)關(guān)鍵詞而已,更深入的可能面試官和面試者都不太了解。

關(guān)于進(jìn)程間通信方式和優(yōu)缺點(diǎn)我之前在【這篇文章】中有過介紹,感興趣的可以移步去看哈。

進(jìn)程間通信有一種[共享內(nèi)存]方式,大家有沒有想過,這種通信方式中如何解決數(shù)據(jù)競(jìng)爭(zhēng)問題?

我們可能自然而然的就會(huì)想到用鎖。但我們平時(shí)使用的鎖都是用于解決線程間數(shù)據(jù)競(jìng)爭(zhēng)問題,貌似沒有看到過它用在進(jìn)程中,那怎么辦?

我找到了兩種方法,信號(hào)量和互斥鎖。

直接給大家貼代碼吧,首先是信號(hào)量方式:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include

constexpr int kMappingSize = 4096;

void sem() {
const char* mapname = "/mapname";
int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

MEOW_DEFER {
if (mapfd > 0) {
close(mapfd);
mapfd = 0;
}
shm_unlink(mapname);
};

if (mapfd == -1) {
perror("shm_open failed \n");
exit(EXIT_FAILURE);
}

if (ftruncate(mapfd, kMappingSize) == -1) {
perror("ftruncate failed \n");
exit(EXIT_FAILURE);
}

void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0);
if (!sp) {
perror("mmap failed \n");
exit(EXIT_FAILURE);
}

sem_t* mutex = (sem_t*)sp;

if (sem_init(mutex, 1, 1) != 0) {
perror("sem_init failed \n");
exit(EXIT_FAILURE);
}

MEOW_DEFER { sem_destroy(mutex); };

int* num = (int*)((char*)sp + sizeof(sem_t));
int cid, proc_count = 0, max_proc_count = 8;
for (int i = 0; i < max_proc_count; ++i) {
cid = fork();
if (cid == -1) {
perror("fork failed \n");
continue;
}
if (cid == 0) {
sem_wait(mutex);
(*num)++;
printf("process %d : %d \n", getpid(), *num);
sem_post(mutex);

if (munmap(sp, kMappingSize) == -1) {
perror("munmap failed\n");
}
close(mapfd);
exit(EXIT_SUCCESS);
}
++proc_count;
}

int stat;
while (proc_count--) {
cid = wait(&stat);
if (cid == -1) {
perror("wait failed \n");
break;
}
}

printf("ok \n");
}

代碼中的MEOW_DEFER我在之前的RAII相關(guān)文章中介紹過,它內(nèi)部的函數(shù)會(huì)在生命周期結(jié)束后觸發(fā)。它的核心函數(shù)其實(shí)就是下面這四個(gè):

int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_post(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_destroy(sem_t *sem);

具體含義大家應(yīng)該看名字就知道,這里的重點(diǎn)就是sem_init中的pshared參數(shù),該參數(shù)為1表示可在進(jìn)程間共享,為0表示只在進(jìn)程內(nèi)部共享。

第二種方式是使用鎖,即pthread_mutex_t,可是pthread_mutex不是用作線程間數(shù)據(jù)競(jìng)爭(zhēng)的嗎,怎么能用在進(jìn)程間呢?

我也是最近才知道,可以給它配置一個(gè)屬性,示例代碼如下:

pthread_mutex_t* mutex;
pthread_mutexattr_t mutexattr;

pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexattr);

它的默認(rèn)屬性是進(jìn)程內(nèi)私有,但是如果給它配置成PTHREAD_PROCESS_SHARED,它就可以用在進(jìn)程間通信中。

完整代碼如下:

void func() {
const char* mapname = "/mapname";
int mapfd = shm_open(mapname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

MEOW_DEFER {
if (mapfd > 0) {
close(mapfd);
mapfd = 0;
}
shm_unlink(mapname);
};

if (mapfd == -1) {
perror("shm_open failed \n");
exit(EXIT_FAILURE);
}

if (ftruncate(mapfd, kMappingSize) == -1) {
perror("ftruncate failed \n");
exit(EXIT_FAILURE);
}

void* sp = mmap(nullptr, kMappingSize, PROT_READ | PROT_WRITE, MAP_SHARED, mapfd, 0);
if (!sp) {
perror("mmap failed \n");
exit(EXIT_FAILURE);
}

pthread_mutex_t* mutex = (pthread_mutex_t*)sp;
pthread_mutexattr_t mutexattr;

pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexattr);

MEOW_DEFER {
pthread_mutexattr_destroy(&mutexattr);
pthread_mutex_destroy(mutex);
};

int* num = (int*)((char*)sp + sizeof(pthread_mutex_t));
int cid, proc_count = 0, max_proc_count = 8;
for (int i = 0; i < max_proc_count; ++i) {
cid = fork();
if (cid == -1) {
perror("fork failed \n");
continue;
}
if (cid == 0) {
pthread_mutex_lock(mutex);
(*num)++;
printf("process %d : %d \n", getpid(), *num);
pthread_mutex_unlock(mutex);

if (munmap(sp, kMappingSize) == -1) {
perror("munmap failed\n");
}
close(mapfd);
exit(EXIT_SUCCESS);
}
++proc_count;
}

int stat;
while (proc_count--) {
cid = wait(&stat);
if (cid == -1) {
perror("wait failed \n");
break;
}
}

printf("ok \n");
}

我想這兩種方式應(yīng)該可以滿足我們?nèi)粘i_發(fā)過程中的大多數(shù)需求。

鎖的方式介紹完之后,可能很多朋友自然就會(huì)想到原子變量,這塊我也搜索了一下。但是也不太確定C++標(biāo)準(zhǔn)中的atomic是否在進(jìn)程間通信中有作用,不過看樣子boost中的atomic是可以用在進(jìn)程間通信中的。

其實(shí)在研究這個(gè)問題的過程中,還找到了一些很多解決辦法,包括:

  • Disabling Interrupts
  • Lock Variables
  • Strict Alternation
  • Peterson's Solution
  • The TSL Instruction
  • Sleep and Wakeup
  • Semaphores
  • Mutexes
  • Monitors
  • Message Passing
  • Barriers

這里我就不過多介紹啦,大家感興趣的可以自行查閱資料哈。

這次的分享就到這里,希望能夠幫助到大家。

參考鏈接

http://husharp.today/2020/12/10/IPC-and-Lock/

https://linux.die.net/man/3/pthread_mutexattr_init

https://www.cnblogs.com/muyi23333/articles/13533291.html

https://man7.org/linux/man-pages/man7/sem_overview.7.html

https://codeantenna.com/a/uXNTzONHZI?


新聞名稱:冷門知識(shí)點(diǎn):進(jìn)程間通信如何加鎖?
地址分享:http://www.dlmjj.cn/article/dpdposs.html