加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Linux进程互斥——临界资源访问

(2009-11-28 22:57:57)
标签:

数据块

if

进程互斥

ipc

to

存储区

模拟临界资源访问的示例程序

本示例的临界资源是一个建立在共享存储区的栈,由服务进程建立并初始化。初始状态下共享栈满,里面顺序放置一系列正整数(自栈顶向下:1,2,3...),代表空闲块号。客户进程利用共享栈进行数据块的分配和释放,以得到、归还一个块号代表,并不进行任何后续操作。程序中getblock过程从共享栈中弹出一个块号(分配),relblock过程把一个已分配块号压入共享栈(释放)。为简单起见,已分配块号在本地也使用栈结构保存,因而每次释放的是最后分配的块号。

编译后执行,第一个进程实例将作为服务进程,提示:

       NO OTHER OPERATION but press Ctrl+C or use kill to end.

服务进程完成初始化后将进入睡眠状态,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。

其他进程实例作为客户进程,进入后首先有命令帮助提示,然后显示命令提示符“?> ”,在命令提示下可以使用的命令包括:

       help 显示可用命令

       list   列出所有已分配块号

       get   分配一个新块

       rel    释放最后分配块号

       end  退出程序

 示例程序的代码如下:

 

#include <sys/types.h>

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/shm.h>

 

#define MY_SHMKEY 10071800      // need to change

#define MAX_BLOCK 1024

#define MAX_CMD 8

 

//共享存储区的栈结构

//为简单起见,已分配块号在本地也使用栈结构local保存

struct shmbuf

{

    int top;

    int stack[MAX_BLOCK];

} *shmptr, local;

 

//

char cmdbuf[MAX_CMD];

int shmid, semid;

 

void sigend(int);

void relblock(void);//释放最后分配块号

void  getblock(void);//分配一个新块

 

void showhelp(void);//显示可用命令

void showlist(void);//列出所有已分配块号

void getcmdline(void);//接受输入命令

 

int main(void)

{

    //建立一个共享存储区

    if((shmid=shmget(MY_SHMKEY, sizeof(struct shmbuf), IPC_CREAT|IPC_EXCL|0666)) < 0)

            

       

 

        //获得共享存储区首地址

        shmid=shmget(MY_SHMKEY, sizeof(struct shmbuf), 0666);

 

        //把一个共享存储区附接到进程内存空间;

        shmptr=(struct shmbuf *)shmat(shmid, 0, 0);

 

        //初始化

        local.top=-1;

 

        //输出命令提示

        showhelp();

        //接受输入命令

        getcmdline();

 

        while(strcmp(cmdbuf,"end\n"))

        {

            if(!strcmp(cmdbuf,"get\n"))

                getblock();

            else if(!strcmp(cmdbuf,"rel\n"))

                relblock();

            else if(!strcmp(cmdbuf,"list\n"))

                showlist();

            else if(!strcmp(cmdbuf,"help\n"))

                showhelp();

 

            //接受输入命令

            getcmdline();

        }

    }

    else       

    {

       

        int i;

        //把一个共享存储区附接到进程内存空间;

        shmptr=(struct shmbuf *)shmat(shmid, 0, 0);

 

        //设置对信号的处理方式或处理过程

        signal(SIGINT, sigend);

        signal(SIGTERM, sigend);

 

        printf("NO OTHER OPERATION but press Ctrl+C or use kill to end.\n");

 

        //初始状态下共享栈满,里面顺序放置一系列正整数(自栈顶向下:,2,3...),

        //代表空闲块号

        shmptr->top=MAX_BLOCK-1;//shmptr->top值越大,可利用物理块就越多

        for(i=0; i<MAX_BLOCK; i++)

            shmptr->stack[i]=MAX_BLOCK-i;

 

        sleep(1000000);

    }

}

 

void sigend(int sig)

{

    shmctl(shmid, IPC_RMID, 0);

    semctl(semid, IPC_RMID, 0);

    exit(0);

}

 

void relblock(void)

{

    if(local.top<0)

    {

            printf("No block to release!");

            return;

    }

    shmptr->top++;

    shmptr->stack[shmptr->top]=local.stack[local.top--];

}

 

void  getblock(void)

{

    if(shmptr->top<0)

    {

            printf("No free block to get!");

            return;

    }

    local.stack[++local.top]=shmptr->stack[shmptr->top];

    shmptr->top--;

}

//显示可用命令

void showhelp(void)

{

    printf("\navailable COMMAND:\n\n");

    printf("help\tlist this help\n");

    printf("list\tlist all gotten block number\n");

    printf("get\tget a new block\n");

    printf("rel\trelease the last gotten block\n");

    printf("end\texit this program\n");

}

 

//列出所有已分配块号

void showlist(void)

{

    int i;

    printf("List all gotten block number:\n");

    for(i=0; i<=local.top;i++)

        printf("%d\t",local.stack[i]);

}

//接受输入命令

void getcmdline(void)

{

    printf("\n?> ");

fgets(cmdbuf, MAX_CMD-1, stdin);

}

2、模拟临界资源访问

实现相应的示例程序功能,记录执行结果,

 

 

运行结果:

 

 

 

 

 

看是否能观察到程序出现错误情况;

不能。

 

改造该程序,使错误情况易于观察到,记录执行情况并进行分析;

分析:

为了使错误易于观察,在分配和释放数据块的函数relblock(void)和 getblock(void)改为如下:

void relblock(void)

{

    if(local.top<0)

    {

            printf("No block to release!");

            return;

    }

    shmptr->top++;

 

    sleep(10);

 

    shmptr->stack[shmptr->top]=local.stack[local.top--];

}

 

void  getblock(void)

{

    if(shmptr->top<0)

    {

            printf("No free block to get!");

            return;

    }

    local.stack[++local.top]=shmptr->stack[shmptr->top];

 

    sleep(10);

 

    shmptr->top--;

}

 

打开两个终端,即两个申请数据块的进程按照如下运行,及结果:

 

1》错误一:两个进程同时申请数据块,即get——get。两个进程同时得到了数据块号3,    而一个数据块只能分配给一个进程,同时还把数据块4丢了,故出现错误。

运行结果如下:

 

进程一:

 

进程二:

 

 

具体执行代码顺序如下:

 

    1>local.stack[++local.top]=shmptr->stack[shmptr->top];

    2>local.stack[++local.top]=shmptr->stack[shmptr->top];

1>shmptr->top--;

2>shmptr->top--;

 

错误二:一个进程释放数据块,一个进程申请数据块时,则出错。

运行结果如下:无效的数据块6,再次被分配,错误。

 

进程一:

 

 

进程二:

 

 

具体执行代码顺序如下:

    1>shmptr->top++;

    2>local.stack[++local.top]=shmptr->stack[shmptr->top];      1>shmptr->stack[shmptr->top]=local.stack[local.top--];

2>shmptr->top--;

 

利用信号量机制实现进程互斥功能,记录执行结果,并进行对比分析。

分析:利用信号量sign来实现同时执行getblock(),即申请数据块。或者先执行relblock()再执行getblock() 即,先申请数据块再申请数据块。的互斥。同理有relblock() 和getblock(),relblock()和getblock()也会出现类似错误。

为了方面实现,在上一个代码基础上,在结构shmbuf的定义中添加了信号量sign的定义。之后在代码中进行pv操作。代码如下:

#include <sys/types.h>

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/shm.h>

 

#define MY_SHMKEY 10071800      // need to change

#define MAX_BLOCK 1024

#define MAX_CMD 8

 

//共享存储区的栈结构

//为简单起见,已分配块号在本地也使用栈结构local保存

struct shmbuf

{

    int top;

    int stack[MAX_BLOCK];

    int sign;

 

} *shmptr, local;

 

//

char cmdbuf[MAX_CMD];

int shmid, semid;

 

void sigend(int);

void relblock(void);//释放最后分配块号

void  getblock(void);//分配一个新块

 

void showhelp(void);//显示可用命令

void showlist(void);//列出所有已分配块号

void getcmdline(void);//接受输入命令

 

int main(void)

{

    //建立一个共享存储区

    if((shmid=shmget(MY_SHMKEY, sizeof(struct shmbuf), IPC_CREAT|IPC_EXCL|0666)) < 0)

            

       

 

        //获得共享存储区首地址

        shmid=shmget(MY_SHMKEY, sizeof(struct shmbuf), 0666);

 

        //把一个共享存储区附接到进程内存空间;

        shmptr=(struct shmbuf *)shmat(shmid, 0, 0);

 

        //初始化

        local.top=-1;

 

        //输出命令提示

        showhelp();

        //接受输入命令

        getcmdline();

 

        while(strcmp(cmdbuf,"end\n"))

        {

            if(!strcmp(cmdbuf,"get\n"))

            {

                while(shmptr->sign==0);

               

                shmptr->sign=0;

                getblock();

                shmptr->sign=1;

            }

            else if(!strcmp(cmdbuf,"rel\n"))

            {

                while(shmptr->sign==0);

               

                shmptr->sign=0;

                relblock();

                shmptr->sign=1;

            }

            else if(!strcmp(cmdbuf,"list\n"))

                showlist();

            else if(!strcmp(cmdbuf,"help\n"))

                showhelp();

 

            //接受输入命令

            getcmdline();

        }

    }

    else       

    {

       

        int i;

        //把一个共享存储区附接到进程内存空间;

        shmptr=(struct shmbuf *)shmat(shmid, 0, 0);

 

        shmptr->sign=1;

 

        //设置对信号的处理方式或处理过程

        signal(SIGINT, sigend);

        signal(SIGTERM, sigend);

 

        printf("NO OTHER OPERATION but press Ctrl+C or use kill to end.\n");

 

        //初始状态下共享栈满,里面顺序放置一系列正整数(自栈顶向下:,2,3...),

        //代表空闲块号

        shmptr->top=MAX_BLOCK-1;//shmptr->top值越大,可利用物理块就越多

        for(i=0; i<MAX_BLOCK; i++)

            shmptr->stack[i]=MAX_BLOCK-i;

 

        sleep(1000000);

    }

}

 

void sigend(int sig)

{

    shmctl(shmid, IPC_RMID, 0);

    semctl(semid, IPC_RMID, 0);

    exit(0);

}

 

void relblock(void)

{

    if(local.top<0)

    {

            printf("No block to release!");

            return;

    }

    shmptr->top++;

 

    sleep(10);//便于观察错误

 

    shmptr->stack[shmptr->top]=local.stack[local.top--];

}

 

void  getblock(void)

{

    if(shmptr->top<0)

    {

            printf("No free block to get!");

            return;

    }

    local.stack[++local.top]=shmptr->stack[shmptr->top];

 

    sleep(10);//便于观察错误

 

    shmptr->top--;

}

//显示可用命令

void showhelp(void)

{

    printf("\navailable COMMAND:\n\n");

    printf("help\tlist this help\n");

    printf("list\tlist all gotten block number\n");

    printf("get\tget a new block\n");

    printf("rel\trelease the last gotten block\n");

    printf("end\texit this program\n");

}

 

//列出所有已分配块号

void showlist(void)

{

    int i;

    printf("List all gotten block number:\n");

    for(i=0; i<=local.top;i++)

        printf("%d\t",local.stack[i]);

}

//接受输入命令

void getcmdline(void)

{

    printf("\n?> ");

    fgets(cmdbuf, MAX_CMD-1, stdin);

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有