IPC API
V1.0
email: mesmerli@hotmail.com
前言
本文介紹 Linux 下,IPC 相關的 API。
- Semaphone: 本文介紹的是使用於Process 之間的同步機制,注意 pthread 與 process 使用不同的 API。
- Shared Memory: 利用共享記憶體機制於 Process 之間傳遞訊息。
- Message: 利用信箱機制於 Process 之間傳遞訊息。
使用 semget 建立 semaphone,每個 semaphore 使用 key 值識別。
相同的 key 值的 semaphone,在不同的 process 之間視為相同的 semaphore
sem1.c
/* After the #includes, the function prototypes and the global variable, we come to the
main function. There the semaphore is created with a call to semget, which returns the
semaphore ID. If the program is the first to be called (i.e. it's called with a parameter
and argc > 1), a call is made to set_semvalue to initialize the semaphore and op_char is
set to X. */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "semun.h"
static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void);
static int sem_id;
int main(int argc, char *argv[])
{
int i;
int pause_time;
char op_char = 'O';
srand((unsigned int)getpid());
sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
if (argc > 1) {
if (!set_semvalue()) {
fprintf(stderr, "Failed to initialize semaphoren");
exit(EXIT_FAILURE);
}
op_char = 'X';
sleep(2);
}
/* Then we have a loop which enters and leaves the critical section ten times.
There, we first make a call to semaphore_p which sets the semaphore to wait, as
this program is about to enter the critical section. */
for(i = 0; i < 10; i++) {
if (!semaphore_p()) exit(EXIT_FAILURE);
printf("%c", op_char);fflush(stdout);
pause_time = rand() % 3;
sleep(pause_time);
printf("%c", op_char);fflush(stdout);
/* After the critical section, we call semaphore_v, setting the semaphore available,
before going through the for loop again after a random wait. After the loop, the call
to del_semvalue is made to clean up the code. */
if (!semaphore_v()) exit(EXIT_FAILURE);
pause_time = rand() % 2;
sleep(pause_time);
}
printf("n%d - finishedn", getpid());
if (argc > 1) {
sleep(10);
del_semvalue();
}
exit(EXIT_SUCCESS);
}
/* The function set_semvalue initializes the semaphore using the SETVAL command in a
semctl call. We need to do this before we can use the semaphore. */
static int set_semvalue(void)
{
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
return(1);
}
/* The del_semvalue function has almost the same form, except the call to semctl uses
the command IPC_RMID to remove the semaphore's ID. */
static void del_semvalue(void)
{
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphoren");
}
/* semaphore_p changes the semaphore by -1 (waiting). */
static int semaphore_p(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_p failedn");
return(0);
}
return(1);
}
/* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
so that the semaphore becomes available. */
static int semaphore_v(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_v failedn");
return(0);
}
return(1);
}
使用 shmget 建立 shared memory 每個 shared memory 使用 key 值識別。
相同的 key 值的 shared memory 在不同的 process 之間視為相同的 shared memory
shm1.c
/* Our first program is a consumer. After the headers the shared memory segment
(the size of our shared memory structure) is created with a call to shmget,
with the IPC_CREAT bit specified. */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
int shmid;
srand((unsigned int)getpid());
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failedn");
exit(EXIT_FAILURE);
}
/* We now make the shared memory accessible to the program. */
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failedn");
exit(EXIT_FAILURE);
}
printf("Memory attached at %Xn", (int)shared_memory);
/* The next portion of the program assigns the shared_memory segment to shared_stuff,
which then prints out any text in written_by_you. The loop continues until end is found
in written_by_you. The call to sleep forces the consumer to sit in its critical section,
which makes the producer wait. */
shared_stuff = (struct shared_use_st *)shared_memory;
shared_stuff->written_by_you = 0;
while(running) {
if (shared_stuff->written_by_you) {
printf("You wrote: %s", shared_stuff->some_text);
sleep( rand() % 4 ); /* make the other process wait for us ! */
shared_stuff->written_by_you = 0;
if (strncmp(shared_stuff->some_text, "end", 3) == 0) {
running = 0;
}
}
}
/* Lastly, the shared memory is detached and then deleted. */
if (shmdt(shared_memory) == -1) {
fprintf(stderr, "shmdt failedn");
exit(EXIT_FAILURE);
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
fprintf(stderr, "shmctl(IPC_RMID) failedn");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
shm2.c
/* The second program is the producer and allows us to enter data for consumers.
It's very similar to shm1.c and looks like this. */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid;
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failedn");
exit(EXIT_FAILURE);
}
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failedn");
exit(EXIT_FAILURE);
}
printf("Memory attached at %Xn", (int)shared_memory);
shared_stuff = (struct shared_use_st *)shared_memory;
while(running) {
while(shared_stuff->written_by_you == 1) {
sleep(1);
printf("waiting for client...n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
shared_stuff->written_by_you = 1;
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
if (shmdt(shared_memory) == -1) {
fprintf(stderr, "shmdt failedn");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
使用 msgget 建立 message queue 每個 message queue 使用 key 值識別。
相同的 key 值的 message queue 在不同的 process 之間視為相同的 message queue
msg1.c
/* Here's the receiver program. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;
/* First, we set up the message queue. */
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %dn", errno);
exit(EXIT_FAILURE);
}
/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %dn", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failedn");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
msg2.c
/* The sender program is very similar to msg1.c. In the main set up, delete the
msg_to_receive declaration and replace it with buffer[BUFSIZ], remove the message
queue delete and make the following changes to the running loop.
We now have a call to msgsnd to send the entered text to the queue. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %dn", errno);
exit(EXIT_FAILURE);
}
while(running) {
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failedn");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
exit(EXIT_SUCCESS);
}
Makefile
CROSS_COMPILE = arm-linux-
LINUXDIR = /usr/src/creator/s3c2410/linux
export LINUXDIR
#
# Include the make variables (CC, etc...)
#
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
export AS LD CC CPP AR
CFLAGS= -O0 -gdwarf-2 -DHAVE_CONFIG_H -DFPM_DEFAULT -Dlinux -Dunix -DNDEBUG -D_REENTRANT -I.
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
.S.o:
$(CC) $(AFLAGS) -c -o $@ $<
all: msg1 msg2 shm1 shm2 sem1
sem1.c: semun.h
shm1.c: shm_com.h
shm2.c: shm_com.h
msg1: msg1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
msg2: msg2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
shm1: shm1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
shm2: shm2.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
sem1: sem1.o
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) -L/usr/local/arm/2.95.3/arm-linux/lib /usr/local/arm/2.95.3/arm-linux/lib/libpthread.a
clean:
rm -f msg1 msg2 shm1 shm2 sem1
0 意見:
張貼留言