PDA

View Full Version : [Linux API] Hướng Dẫn Kỹ Thuật Inter Process Memory và semaphore Nhiều Process



AlexF
21-04-2011, 11:06 PM
Để đồng bộ và chia sẻ dữ liệu giữa nhiều process, hệ điều hành đưa ra khái niệm Inter process Memory ( trên windows cũng có khái niệm này)

dưới đây là 1 ví dụ trong đó file server.c có nhiệm vụ chạy trước và đợi khi nào file client.c nhảy qua phần truyền signal cho server thì server sẽ nhận gói tin của client gửi cho và in ra màn hình


#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define SEMKEYPATH "/dev/null" /* Path used on ftok for semget key */
#define SEMKEYID 1 /* Id used on ftok for semget key */
#define SHMKEYPATH "/dev/null" /* Path used on ftok for shmget key */
#define SHMKEYID 1 /* Id used on ftok for shmget key */

#define NUMSEMS 2 /* Num of sems in created sem set */
#define SIZEOFSHMSEG 50 /* Size of the shared mem segment */

#define NUMMSG 2 /* Server only doing two "receives"
on shm segment */

int main(int argc, char *argv[])
{
int rc, semid, shmid, i;
key_t semkey, shmkey;
void *shm_address;
struct sembuf operations[2];
struct shmid_ds shmid_struct;
short sarray[NUMSEMS];

/* Generate an IPC key for the semaphore set and the shared */
/* memory segment. Typically, an application specific path and */
/* id would be used to generate the IPC key. */
semkey = ftok(SEMKEYPATH,SEMKEYID);
if ( semkey == (key_t)-1 )
{
printf("main: ftok() for sem failed\n");
return -1;
}
shmkey = ftok(SHMKEYPATH,SHMKEYID);
if ( shmkey == (key_t)-1 )
{
printf("main: ftok() for shm failed\n");
return -1;
}

/* Create a semaphore set using the IPC key. The number of */
/* semaphores in the set is two. If a semaphore set already */
/* exists for the key, return an error. The specified permissions*/
/* give everyone read/write access to the semaphore set. */

semid = semget( semkey, NUMSEMS, 0666 | IPC_CREAT | IPC_EXCL );
if ( semid == -1 )
{
printf("main: semget() failed\n");
return -1;
}

/* Initialize the first semaphore in the set to 0 and the */
/* second semaphore in the set to 0. */
/* */
/* The first semaphore in the sem set means: */
/* '1' -- The shared memory segment is being used. */
/* '0' -- The shared memory segment is freed. */
/* The second semaphore in the sem set means: */
/* '1' -- The shared memory segment has been changed by */
/* the client. */
/* '0' -- The shared memory segment has not been */
/* changed by the client. */

sarray[0] = 0;
sarray[1] = 0;


/* The '1' on this command is a no-op, because the SETALL command*/
/* is used. */
rc = semctl( semid, 1, SETALL, sarray);
if(rc == -1)
{
printf("main: semctl() initialization failed\n");
return -1;
}

/* Create a shared memory segment using the IPC key. The */
/* size of the segment is a constant. The specified permissions */
/* give everyone read/write access to the shared memory segment. */
/* If a shared memory segment already exists for this key, */
/* return an error. */
shmid = shmget(shmkey, SIZEOFSHMSEG, 0666 | IPC_CREAT | IPC_EXCL);
if (shmid == -1)
{
printf("main: shmget() failed\n");
return -1;
}

/* Attach the shared memory segment to the server process. */
shm_address = shmat(shmid, NULL, 0);
if ( shm_address==NULL )
{
printf("main: shmat() failed\n");
return -1;
}
printf("Ready for client jobs\n");

/* Loop only a specified number of times for this example. */
for (i=0; i < NUMMSG; i++)
{
/* Set the structure passed into the semop() to first wait */
/* for the second semval to equal 1, then decrement it to */
/* allow the next signal that the client writes to it. */
/* Next, set the first semaphore to equal 1, which means */
/* that the shared memory segment is busy. */
operations[0].sem_num = 1;
/* Operate on the second sem */
operations[0].sem_op = -1;
/* Decrement the semval by one */
operations[0].sem_flg = 0;
/* Allow a wait to occur */

operations[1].sem_num = 0;
/* Operate on the first sem */
operations[1].sem_op = 1;
/* Increment the semval by 1 */
operations[1].sem_flg = IPC_NOWAIT;
/* Do not allow to wait */

rc = semop( semid, operations, 2 );
if (rc == -1)
{
printf("main: semop() failed\n");
return -1;
}

/* Print the shared memory contents. */
printf("Server Received : \"%s\"\n", (char *) shm_address);

/* Signal the first semaphore to free the shared memory. */
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = IPC_NOWAIT;

rc = semop( semid, operations, 1 );
if (rc == -1)
{
printf("main: semop() failed\n");
return -1;
}

} /* End of FOR LOOP */

/* Clean up the environment by removing the semid structure, */
/* detaching the shared memory segment, and then performing */
/* the delete on the shared memory segment ID. */

rc = semctl( semid, 1, IPC_RMID );
if (rc==-1)
{
printf("main: semctl() remove id failed\n");
return -1;
}
rc = shmdt(shm_address);
if (rc==-1)
{
printf("main: shmdt() failed\n");
return -1;
}
rc = shmctl(shmid, IPC_RMID, &shmid_struct);
if (rc==-1)
{
printf("main: shmctl() failed\n");
return -1;
}
return 0;
}



Client.c



#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define SEMKEYPATH "/dev/null" /* Path used on ftok for semget key */
#define SEMKEYID 1 /* Id used on ftok for semget key */
#define SHMKEYPATH "/dev/null" /* Path used on ftok for shmget key */
#define SHMKEYID 1 /* Id used on ftok for shmget key */

#define MESSAGE_SEND "Day La Doan Text Cua Client Duoc Send Cho Server"
#define NUMSEMS 2
#define SIZEOFSHMSEG 50

int main(int argc, char *argv[])
{
struct sembuf operations[2];
void *shm_address;
int iSemid, iShmid, iRc;
key_t key_tSemkey, key_tShmkey;
/* Generate an IPC key for the semaphore set and the shared */
/* memory segment. Typically, an application specific path and */
/* id would be used to generate the IPC key. */
key_tSemkey = ftok(SEMKEYPATH,SEMKEYID);
if ( key_tSemkey == (key_t)-1 )
{
printf("main: ftok() for sem failed\n");
return -1;
}
key_tShmkey = ftok(SHMKEYPATH,SHMKEYID);
if ( key_tShmkey == (key_t)-1 )
{
printf("main: ftok() for shm failed\n");
return -1;
}
/* Get the already created semaphore ID associated with key. */
/* If the semaphore set does not exist, then it will not be */
/* created, and an error will occur. */
iSemid = semget( key_tSemkey, NUMSEMS, 0666);
if ( iSemid == -1 )
{
printf("main: semget() failed\n");
return -1;
}
/* Get the already created shared memory ID associated with key. */
/* If the shared memory ID does not exist, then it will not be */
/* created, and an error will occur. */
iShmid = shmget(key_tShmkey, SIZEOFSHMSEG, 0666);
if (iShmid == -1)
{
printf("main: shmget() failed\n");
return -1;
}
/* Attach the shared memory segment to the client process. */
shm_address = shmat(iShmid, NULL, 0);
if ( shm_address==NULL )
{
printf("main: shmat() failed\n");
return -1;
}
/* First, check to see if the first semaphore is a zero. If it */
/* is not, it is busy right now. The semop() command will wait */
/* for the semaphore to reach zero before running the semop(). */
/* When it is zero, increment the first semaphore to show that */
/* the shared memory segment is busy. */
operations[0].sem_num = 0;
/* Operate on the first sem */
operations[0].sem_op = 0;
/* Wait for the value to be=0 */
operations[0].sem_flg = 0;
/* Allow a wait to occur */
operations[1].sem_num = 0;
/* Operate on the first sem */
operations[1].sem_op = 1;
/* Increment the semval by one */
operations[1].sem_flg = 0;
/* Allow a wait to occur */
iRc = semop( iSemid, operations, 2 );
if (iRc == -1)
{
printf("main: semop() failed\n");
return -1;
}
strcpy((char *) shm_address, MESSAGE_SEND);
/* Release the shared memory segment by decrementing the in-use */
/* semaphore (the first one). Increment the second semaphore to */
/* show that the client is finished with it. */
operations[0].sem_num = 0;
/* Operate on the first sem */
operations[0].sem_op = -1;
/* Decrement the semval by one */
operations[0].sem_flg = 0;
/* Allow a wait to occur */
operations[1].sem_num = 1;
/* Operate on the second sem */
operations[1].sem_op = 1;
/* Increment the semval by one */
operations[1].sem_flg = 0;
/* Allow a wait to occur */
iRc = semop( iSemid, operations, 2 );
if (iRc == -1)
{
printf("main: semop() failed\n");
return -1;
}
/* Detach the shared memory segment from the current process. */
iRc = shmdt(shm_address);
if (iRc==-1)
{
printf("main: shmdt() failed\n");
return -1;
}
return 0;
}


Hoặc để đơn giản, bạn có thể tham khảo code này



#include <unistd.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

union semun
{ //cau truc su dung voi ham semctl
int val;
struct semid_ds *buf;
unsigned short int *array;
};

#define SEMID 4321
#define SHMID 1234
#define MAX_LEN 256

int main(int argc,char *argv[])
{
int id, semid;
char * shm_addr;
int * size;
char * msg;
union semun semopts;
struct sembuf sb;
// tao vung nho chung
id = shmget(SHMID , MAX_LEN, IPC_CREAT | 0777);
// attach
shm_addr = shmat(id , NULL , 0);
// tao semaphore
semid = semget(SEMID , 1, 0777);
// khoi tao semaphore = 1
semopts.val = 1;
semctl(semid, 0 , SETVAL, semopts);
// giam semaphore di 1, cho ghi du lieu
sb.sem_num = 0;
sb.sem_op = -1;
sb. sem_flg = 0;
semop(semid, &sb, 1);
// ghi du lieu vao vung nho chung
strcpy(msg,"From Process A");
size = (int *)shm_addr;
*size = sizeof(msg);
strcpy(shm_addr + sizeof(int), msg);
// tang semaphore len 1 , cho phep doc du lieu
sb.sem_op = 1;
semop(semid, &sb, 1);
//detach
shmdt(shm_addr);
return 0;
}

}


#include <unistd.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>


#define SEMID 4321
#define SHMID 1234
#define MAX_LEN 256


int main(int argc,char *argv[])
{
int id, semid;
char * shm_addr;
int * size;
char * msg;
union semun semval;
struct sembuf sb;

// tao vung nho chung
id = shmget(SHMID , MAX_LEN, 0777);
// attach
shm_addr = shmat(id , NULL , 0);
// tao semaphore
semid = semget(SEMID , 1, 0777);
// giam semaphore di 1, cho doc du lieu
sb.sem_num = 0;
sb.sem_op = -1;
sb. sem_flg = 0;
semop(semid, &sb, 1);

// doc du lieu tu vung nho chung
size = (int *)shm_addr;
strncpy(msg, shm_addr + sizeof(int) , *size);

// tang semaphore len 1 , cho phep ghi du lieu
sb.sem_op = 1;
semop(semid, &sb, 1);

printf("Process B received: %s", msg);
//detach
shmdt(shm_addr);
return 0;
}

http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/understandlk-chp-19-sect-3.html