#通过四个进程实现两个程序可以互相发送信息的功能
视为 part 1 中的升级版!
注意,此项操作关系到内核,所以需要在home目录或者根目录先进行创建
创建程序#1:
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define MSGKEY 2048
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
int ret;
int msgid;
msgid = msgget( MSGKEY,IPC_CREAT | IPC_EXCL );
if( -1 == msgid )
{
perror("msgget");
exit(1);
}
pid_t pid = fork();
if( -1 == pid )
{
perror("fork");
exit(1);
}
else if ( 0 == pid )
{
while(1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 2;
scanf("%s",mbuf.mtext);
ret = msgsnd( msgid, &mbuf, sizeof(mbuf.mtext), 0 );
if( -1 == ret )
{
perror("msgsnd");
exit(1);
}
if( !strcmp(mbuf.mtext,"bye") )
{
mbuf.mtype = 1;
ret = msgsnd( msgid, &mbuf, sizeof(mbuf.mtext), 0 );
break;
}
}
}
else
{
while(1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 1;
ret = msgrcv( msgid, &mbuf, sizeof(mbuf.mtext), 1, 0 );
if( -1 == ret )
{
perror("msgsnd");
exit(1);
}
if( !strcmp(mbuf.mtext,"bye") )
{
kill( pid, 2 );
break;
}
printf("\t\t%s\n",mbuf.mtext);
}
}
sleep(1);
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
创建程序#2
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define MSGKEY 2048
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[64]; /* message data */
};
int main()
{
struct msgbuf mbuf;
int ret;
int msgid;
msgid = msgget( MSGKEY, 0 );
if( -1 == msgid )
{
perror("msgget");
exit(1);
}
pid_t pid = fork();
if( -1 == pid )
{
perror("fork");
exit(1);
}
else if ( 0 == pid )
{
while(1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 1;
scanf("%s",mbuf.mtext);
ret = msgsnd( msgid, &mbuf, sizeof(mbuf.mtext), 0 );
if( -1 == ret )
{
perror("msgsnd");
exit(1);
}
if( !strcmp(mbuf.mtext,"bye") )
{
mbuf.mtype = 2;
msgsnd( msgid, &mbuf, sizeof(mbuf.mtext), 0 );
break;
}
}
}
else
{
while(1)
{
memset(&mbuf, 0, sizeof(mbuf));
mbuf.mtype = 2;
ret = msgrcv( msgid, &mbuf, sizeof(mbuf.mtext), 2, 0 );
if( -1 == ret )
{
perror("msgsnd");
exit(1);
}
if( !strcmp(mbuf.mtext,"bye") )
{
kill( pid, 2 );
break;
}
printf("\t\t%s\n",mbuf.mtext);
}
}
return 0;
}
#内存共享
共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。
功能和效果:首先运行程序A,那么A中的整形数据count会自加,延迟usleep(1000 000) = 1s,此时在运行程序B(通过A复制而来并进行过删减修改)那么B中的count也会自加。但此时应为共享内存的原因,A和B中的count 会 “你来我往” 的个加1,从而B开始运行时,A会自增加 2个,B也会自增加 2个。并且程序B中的count 会从A 已经打印出的数字之后 开始自加 2,程序A也是如此。
代码演示:
程序A:
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#define SHMKEY 1024
#define SHMSIZE 4096
int main()
{
int shmid;
void *shmaddr;
int count = 0;
shmid = shmget( SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL );
if( -1 == shmid )
{
perror("shmget");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0);
if( NULL == shmaddr )
{
perror("shmat");
exit(1);
}
*(int *)shmaddr = count;
while(1)
{
count = *(int *)shmaddr;
if(count >= 100)
{
break;
}
printf("Process A : count = %d\n",count );
count ++;
*(int *)shmaddr = count;
usleep(1000000);
}
shmctl(shmid, IPC_RMID ,0);
return 0;
}
程序B:
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#define SHMKEY 1024
#define SHMSIZE 4096
int main()
{
int shmid;
void *shmaddr;
int count = 0;
shmid = shmget( SHMKEY, SHMSIZE, 0 );
if( -1 == shmid )
{
perror("shmget");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0);
if( NULL == shmaddr )
{
perror("shmat");
exit(1);
}
while(1)
{
count = *(int *)shmaddr;
if(count >= 100)
{
break;
}
printf("Process B : count = %d\n",count );
count ++;
*(int *)shmaddr = count;
usleep(1000000);
}
return 0;
}
请在这里注意:
代码 "usleep(1000 000)"的位置。如果将 "usleep(1000 000)" 置于
count = *(int *)shmaddr;
和
*(int *)shmaddr = count;
之间的话,将不会出现自加 2 的效果。就需要自己体会来解释。
************************************************************************************************************************************
************************************************************************************************************************************
#信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。
接下来将 信号量 添加 进置上方代码,但是运行的效果不变。
程序A:
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define SHMKEY 1024
#define SEMKEY 1024
#define SHMSIZE 4096
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 sem_p(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if( -1 == ret )
{
perror("semop");
return;
}
}
void sem_v(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0;
sbuf.sem_op = 1;
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if( -1 == ret )
{
perror("semop");
return;
}
}
int main()
{
int shmid,semid,ret;
void *shmaddr;
int count = 0;
shmid = shmget( SHMKEY, SHMSIZE, IPC_CREAT | IPC_EXCL );
if( -1 == shmid )
{
perror("shmget");
exit(1);
}
semid = semget(SEMKEY, 1, IPC_CREAT | IPC_EXCL );
if( -1 == semid )
{
perror("semget");
exit(1);
}
union semun unsem;
unsem.val = 1;
ret = semctl( semid, 0, SETVAL, unsem );
if( -1 == ret )
{
perror("semctl");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0);
if( NULL == shmaddr )
{
perror("shmat");
exit(1);
}
*(int *)shmaddr = count;
while(1)
{
sem_p(semid);
count = *(int *)shmaddr;
usleep(1000000);
if(count >= 100)
{
break;
}
printf("Process A : count = %d\n",count );
count ++;
*(int *)shmaddr = count;
sem_v(semid);
}
shmdt(shmaddr);
shmctl(shmid, IPC_RMID ,0);
semctl(semid, 0, IPC_RMID);
return 0;
}
程序B:
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define SHMKEY 1024
#define SEMKEY 1024
#define SHMSIZE 4096
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 sem_p(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if( -1 == ret )
{
perror("semop");
return;
}
}
void sem_v(int semid)
{
int ret;
struct sembuf sbuf;
sbuf.sem_num = 0;
sbuf.sem_op = 1;
sbuf.sem_flg = SEM_UNDO;
ret = semop(semid, &sbuf, 1);
if( -1 == ret )
{
perror("semop");
return;
}
}
int main()
{
int shmid,semid,ret;
void *shmaddr;
int count = 0;
shmid = shmget( SHMKEY, SHMSIZE, 0 );
if( -1 == shmid )
{
perror("shmget");
exit(1);
}
semid = semget(SEMKEY, 1, 0 );
if( -1 == semid )
{
perror("semget");
exit(1);
}
shmaddr = shmat(shmid, NULL, 0);
if( NULL == shmaddr )
{
perror("shmat");
exit(1);
}
*(int *)shmaddr = count;
while(1)
{
sem_p(semid);
count = *(int *)shmaddr;
usleep(1000000);
if(count >= 100)
{
break;
}
printf("Process B : count = %d\n",count );
count ++;
*(int *)shmaddr = count;
sem_v(semid);
}
shmdt(shmaddr);
return 0;
}
这里注意:
代码 "ulseep(1000 000)" 置于
count = *(int *)shmaddr;
和
*(int *)shmaddr = count;
之间,才会运行相同的效果。
如果将 "usleep(1000 000)" 放回
*(int *)shmaddr = count;
的下方,
则会出现这样的效果:程序A先开始运行,count自加 1。此时运行程序B。两边的 count 开始自加 2。但程序 A 的count将会在程序B开始时跳回至 ”0“ 开始自加 2,程序 B 的count 将会从 "2" 开始自加 2。需要自己体会理解。