实验四 Linux进程互斥
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验四 Linux进程互斥
一、实验目的
熟悉Linux下信号量机制,能够使用信号量实现在并发进程间的互斥和同步。
二、实验题目
使用共享存储区机制,使多个并发进程分别模拟生产者-消费者模式同步关系、临界资源的互斥访问关系,使用信号量机制实现相应的同步和互斥。
三、背景材料
(一)需要用到的系统调用
实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。
fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行;
wait() 等待子进程执行完成;
shmget() 建立一个共享存储区;
shmctl() 操纵一个共享存储区;
s hmat() 把一个共享存储区附接到进程内存空间;
shmdt() 把一个已经附接的共享存储区从进程内存空间断开;
semget() 建立一个信号量集;
semctl() 操纵一个信号量集,包括赋初值;
semop() 对信号量集进行wait和signal操作;
signal() 设置对信号的处理方式或处理过程。
(二)模拟生产者-消费者的示例程序
本示例主要体现进程间的直接制约关系,由于使用共享存储区,也存在间接制约关系。进程分为服务进程和客户进程,服务进程只有一个,作为消费者,在每次客户进程改变共享存储区内容时显示其数值。各客户进程作为生产者,如果共享存储区内容已经显示(被消费),可以接收用户从键盘输入的整数,放在共享存储区。
编译后执行,第一个进程实例将作为服务进程,提示:
ACT CONSUMER!!! To end, try Ctrl+C or use kill.
服务进程一直循环执行,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。
其他进程实例作为客户进程,提示:
Act as producer. To end, input 0 when prompted.
客户进程一直循环执行,直到用户输入0。
示例程序代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#define MY_S HM KEY 10071500 // need to change
#define MY_S EM KEY 10071500 // need to change
void sigend(int);
int shmid, semid;
int main(void)
{
int *shmptr, semval, local;
struct sembuf semopbuf;
/*这个函数成功时返回共享内存的ID,失败时返回-1。*/
if((shmid=shmget(MY_SHMKEY, sizeof(int), IPC_CREA T|IPC_EXCL|0666)) < 0)
{ /* shared memory exists, act as client */
shmid=shmget(MY_SHMKEY, sizeof(int), 0666);
//建立一个信号量集函数执行成功,则返回信号量集的标识符(一个大于等于0的整数),失败,则返回–1
semid=semget(MY_SEMKEY, 2, 0666);
//返回共享内存的起始地址。失败时返回-1。允许本进程使用这块共享内存
shmptr=(int *)shmat(shmid, 0, 0);
printf("Act as producer. To end, input 0 when prompted.\n\n");
printf("Input a number:\n");
scanf("%d", &local);
while( local )
{
semopbuf.sem_num=0;
semopbuf.sem_op=-1;
semopbuf.sem_flg=SEM_UNDO;
semop(semid, &semopbuf, 1); /* P(S1)对信号量集进行wait和signal操作;*/
*shmptr = local;
semopbuf.sem_num=1;// 正数:释放相应的资源数,将sem_op的值加到信号量的值上
semopbuf.sem_op=1;//执行释放的资源
semopbuf.sem_flg=SEM_UNDO;
semop(semid, &semopbuf, 1); /* V(S2) */
printf("Input a number:\n");
scanf("%d", &local);
}
}
else /* acts as server */
{
//建立一个信号量集;
//参数nsems表示创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。
semid=semget(MY_SEMKEY, 2, IPC_CREA T|0666);
shmptr=(int *)shmat(shmid, 0, 0);
semval=1;
//操纵一个信号量集,包括赋初值;SETVAL设置信号量集中的一个单独的信号量的值 semctl(semid, 0, SETV AL, semval); /* set S1=1第二个参数是信号量数目*/
semval=0;
semctl(semid, 1, SETV AL, semval); /* set S2=0 */
//对信号的处理方式或处理过程
signal(SIGINT, sigend);由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程按下CTRL+C产生SIGINT
signal(SIGTERM, sigend);请求中止进程,kill命令缺省发送
printf("ACT CONSUMER!!! To end, try Ctrl+C or use kill.\n\n");
while(1)
{
semopbuf.sem_num=1;
semopbuf.sem_op=-1;
semopbuf.sem_flg=SEM_UNDO;
semop(semid, &semopbuf, 1); /* P(S2) */
printf("Shared memory set to %d\n", *shmptr);
semopbuf.sem_num=0;
semopbuf.sem_op=1;
semopbuf.sem_flg=SEM_UNDO;
semop(semid, &semopbuf, 1); /* V(S1) */
}
}
}
void sigend(int sig)
{
shmctl(shmid, IPC_RMID, 0);
semctl(semid, IPC_RMID, 0);
exit(0);
}
(三)模拟临界资源访问的示例程序
本示例的临界资源是一个建立在共享存储区的栈,由服务进程建立并初始化。初始状态下共享栈满,里面顺序放置一系列正整数(自栈顶向下:1,2,3...),代表空闲块号。客户进程利用共享栈进行数据块的分配和释放,以得到、归还一个块号代表,并不进行任何后续操作。程序中getblock过程从共享栈中弹出一个块号(分配),relblock过程把一个已分配块号压入共享栈(释放)。为简单起见,已分配块号在本地也使用栈结构保存,因而每次释放的是最后分配的块号。
编译后执行,第一个进程实例将作为服务进程,提示:
NO OTHER OPERA TION but press Ctrl+C or use kill to end.