訊號量、訊息佇列、共享記憶體複習
訊號量程式碼
使用訊號量實現父子程式間同步:
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
void pv(int sem_id, int op)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = op;
sem_b.sem_flg = SEM_UNDO;
semop(sem_id, &sem_b, 1);
}
int main(int argc, char** argv)
{
int sem_id = semget(IPC_PRIVATE, 1, 0666);
union semun sem_un;
sem_un.val = 1;
semctl(sem_id, 0, SETVAL, sem_un);
pid_t pid = fork();
if(pid < 0)
return -1;
else if(pid == 0){
printf("child try to get binary sem\n");
pv(sem_id, -1);
printf("child get the sem and would release it after 5 seconds\n");
sleep(5);
pv(sem_id, 1);
exit(0);
}
else{
printf("parent try to get binary sem\n");
pv(sem_id, -1);
printf("parent get the sem and would release it agter 5 seocnds\n");
sleep(5);
pv(sem_id, 1);
}
waitpid(pid, NULL, 0);
semctl(sem_id, 0, IPC_RMID, sem_un);
return 0;
}
訊息佇列程式碼
使用訊息佇列實現簡單的程式間交談。
utili.h標頭檔案:
#pragma once
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
const char* const PATH_NAME = "pathname";
const int PRO_ID = 0xff;
const int BUFFER_SIZE = 256;
struct message {
long msg_type;
char msg_text[BUFFER_SIZE];
};
server.cpp:
#include "utili.h"
const int SERVER_MSG_SND_TYPE = 10000;
const int SERVER_MSG_RCV_TYPE = 2;
int main()
{
int msg_id;
if(msg_id = msgget(ftok(PATH_NAME, PRO_ID), IPC_CREAT | IPC_EXCL | 0755) < 0){
perror("what");
exit(-1);
}
printf("msg_id = %d\n", msg_id);
message msg;
for(; ;){
printf("server:>");
scanf("%s", msg.msg_text);
if(strncasecmp(msg.msg_text, "quit", 4) == 0)
break;
msg.msg_type = SERVER_MSG_SND_TYPE;
msgsnd(msg_id, &msg, strlen(msg.msg_text)+1, 0);
msgrcv(msg_id, &msg, BUFFER_SIZE, SERVER_MSG_RCV_TYPE, 0);
printf("client:>%s\n", msg.msg_text);
}
msgctl(msg_id, IPC_RMID, 0);
while(1);
exit(0);
客戶端:
#include "utili.h"
const int CLIENT_MSG_SND_TYPE = 2;
const int CLIENT_MSG_RCV_TYPE = 10000;
int main()
{
int msg_id;
key_t msg_key = ftok(PATH_NAME, PRO_ID);
if(msg_key < 0){
perror("what1");
exit(-1);
}
printf("msg_key = %d\n", msg_key);
if((msg_id = msgget(msg_key, 0)) < 0){
perror("what2");
exit(-1);
}
printf("mid_id = %d\n", msg_id);
message msg;
for(; ;){
msgrcv(msg_id, &msg, BUFFER_SIZE, CLIENT_MSG_RCV_TYPE, 0);
printf("serverhehf:>%s\n", msg.msg_text);
printf("clientwowo:>");
scanf("%s", msg.msg_text);
if(strncasecmp(msg.msg_text, "quit", 4) == 0)
break;
msg.msg_type = CLIENT_MSG_SND_TYPE;
msgsnd(msg_id, &msg, strlen(msg.msg_text)+1, 0);
}
msgctl(msg_id, IPC_RMID, 0);
exit(0);
}
雙反接收和傳送的訊息型別不同,可以利用這點從訊息佇列中取自己的訊息。
昨天晚上寫訊息佇列這個程式坑了我好長時間,沒有使用perror判斷錯誤外加沒有注意到ftok函式針對的path必須是真實存在的檔案或目錄,然後找BUG找了一個半多小時。
共享記憶體程式碼
這裡使用共享記憶體來實現伺服器和客戶端通訊,並且由於共享了讀寫,使用訊號量來同步。
utili.h:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#define PATHNAME "newfile"
#define PRO_ID 0xff
#define err_exit(m) \
do{ \
perror(m); \
exit(1); \
}while(0)
#define USE_SEM
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO*/
};
server.cpp:
#include "utili.h"
int main(int argc, char** argv)
{
int shm_id;
if( (shm_id = shmget(ftok(PATHNAME, PRO_ID), 1024,
IPC_CREAT|IPC_EXCL|0755)) < 0)
err_exit("shmget err.");
char *ch;
if( (ch = (char *)shmat(shm_id, NULL, 0)) == (void *)-1)
err_exit("shmat err");
#ifdef USE_SEM
int sem_id;
if( (sem_id = semget(ftok(PATHNAME, PRO_ID), 2, IPC_CREAT|IPC_EXCL|0755)) < 0){
shmdt(ch);
shmctl(shm_id, IPC_RMID, 0);
err_exit("semget err.");
}
union semun init;
init.val = 0;
semctl(sem_id, 0, SETVAL, init); //0
semctl(sem_id, 1, SETVAL, init); //1
struct sembuf p = {0, -1, 0}, v = {1, 1, 0};
#endif
for(; ;){
printf("server:>");
scanf("%s", ch);
if(strncasecmp(ch, "quit", 4) == 0){
shmdt(ch);
break;
}
semop(sem_id, &v, 1);
semop(sem_id, &p, 1);
printf("client:>%s\n", ch);
}
int res;
if( (res = shmctl(shm_id, IPC_RMID, 0)) < 0)
err_exit("remove err.");
return 0;
}
client.cpp:
#include "utili.h"
int main(int argc, char** argv)
{
int shm_id;
if( (shm_id = shmget(ftok(PATHNAME, PRO_ID), 0, 0)) < 0)
err_exit("shmget err.");
char *ch;
if( (ch = (char *)shmat(shm_id, NULL, 0)) == (void *)-1)
err_exit("shmat err");
#ifdef USE_SEM
int sem_id;
if( (sem_id = semget(ftok(PATHNAME, PRO_ID), 0, 0)) < 0){
shmdt(ch);
shmctl(shm_id, IPC_RMID, 0);
err_exit("semget err.");
}
union semun init;
init.val = 0;
semctl(sem_id, 0, SETVAL, init); //0
semctl(sem_id, 1, SETVAL, init); //1
struct sembuf p = {1, -1, 0}, v = {0, 1, 0};
#endif
for(; ;){
semop(sem_id, &p, 1);
printf("server:>%s\n", ch);
printf("cli:>");
scanf("%s", ch);
if(strncasecmp(ch, "quit", 4) == 0){
shmdt(ch);
break;
}
semop(sem_id, &v, 1);
}
int res;
if( (res = shmctl(shm_id, IPC_RMID, 0)) < 0)
err_exit("remove err.");
return 0;
}
相關文章
- 程式間通訊——基於共享記憶體和訊號量實現共享佇列記憶體佇列
- 分散式之訊息佇列複習精講分散式佇列
- 訊息佇列系列一:訊息佇列應用佇列
- 訊息佇列佇列
- 訊息佇列學習基礎佇列
- 訊息佇列學習腦圖佇列
- 分散式訊息佇列:如何保證訊息不被重複消費?(訊息佇列消費的冪等性)分散式佇列
- kafka 訊息佇列Kafka佇列
- 訊息佇列(MQ)佇列MQ
- [Redis]訊息佇列Redis佇列
- [訊息佇列]rocketMQ佇列MQ
- [訊息佇列]RabbitMQ佇列MQ
- Kafka訊息佇列Kafka佇列
- RabbitMQ訊息佇列MQ佇列
- 訊息佇列Kafka學習總結佇列Kafka
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型
- RabbitMQ訊息佇列(五):Routing 訊息路由MQ佇列路由
- 全面理解Handler-1:理解訊息佇列,手寫訊息佇列佇列
- 程式間通訊--訊息佇列佇列
- ORACLE在各作業系統訊號量與共享記憶體的維護Oracle作業系統記憶體
- 訊息機制篇——初識訊息與訊息佇列佇列
- rabbitmq訊息佇列原理MQ佇列
- 訊息佇列之 RocketMQ佇列MQ
- 訊息佇列二三事佇列
- MQ訊息佇列_RabbitMQMQ佇列
- 訊息佇列設計佇列
- 訊息佇列深入解析佇列
- 訊息佇列之 ActiveMQ佇列MQ
- 訊息佇列之RocketMQ佇列MQ
- 訊息佇列雜談佇列
- 訊息佇列之RabbitMQ佇列MQ
- 訊息佇列簡史佇列
- 淺談訊息佇列及常見的訊息中介軟體佇列
- 微服務學習計劃——訊息佇列微服務佇列
- Redis 學習筆記(六)Redis 如何實現訊息佇列Redis筆記佇列
- 程序間通訊(2)-訊息佇列佇列
- 什麼是訊息佇列?佇列
- 訊息佇列mq總結佇列MQ
- Python使用RocketMQ(訊息佇列)PythonMQ佇列