CSDN博客

img ryman

操作系统多线程的完全编程

发表于2004/12/31 14:54:00  1321人阅读

操作系统多线程的完全编程

一,设计要求

    有界缓冲区内设有10个存储单元,放入/取出的数据项设定为1~10这10个整形数。要求每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者标识符。

 

二,实验环境

服务器:linux

客户端:windows98+telnet

开发语言:c

 

三,设计思想

通过本程序实现对生产者与消费者的同步运行,有效的控制它们对有界缓冲区的操作。本程序的实现涉及到两个主要问题,一,就是怎么实现生产着与消费者的互斥操作。二,怎么实现对10个缓冲区的充分利用。

本程序的设计思想大体如下:

     有界缓冲区就一个一维长度为10的数组,用两个指针inout来控制该区哪里的数据,往哪里添加数据。In用与指向最后放进去的数据,out用于指向第一个放进去的数据。

     所以用以下算法就可以实现对10缓冲区的100%利用。

     if(in==out&&buffer[in]==0)/*判断是否是缓冲没数据,此时的in指针不向后移*/

        buffer[in]=nextproduced;

    else                       /*否则in指针向后移一位*/     

    {        

     buffer[(in+1)%BUFFER_SIZE]=nextproduced;

     in=(in+1)%BUFFER_SIZE;

    }

以上为添加数据的控制,以下是消费数据的控制。

if(in==out&&buffer[out]!=0)/*判断in与out是否指向一个区,且不为空,此时out指针不移动*/

      buffer[out]=0;

   else                     /*否则,out指针向后移一位*/

   {      

    buffer[out]=0;    

    out=(out+1)%BUFFER_SIZE;

    }

    对于进程的互斥可以用信号灯semaphore实现,本程序用sem_t定义了一个信号灯sem,在生产中使用sem_post(&sem),消费者中使用sem_wait(&sem)实现了只有先生产有足够的资源时,消费者才能消费。

 

四,调试报告

在调试过程中出现了不少的语法上的错误与逻辑上的错误,以下我选摘了一部分问题并加一解释。

windows下使用turboc2编译程序的时候使用random函数是可以直接通过参数的形式传递给random,如random(10)产生0-9的随机数,但如果在linux中这样使用的话就会出现以下错误提示:course_design.c: In function `produce':

course_design.c:21: too many arguments to function `random'

故后来改为用random()%10+1这样的方式来产生1-10的随机数。

 

course_design.c:13: parse error before "sem"

course_design.c:13: warning: data definition has no type or storage class

少了头文件#include"semaphore.h"

 

course_design.c: In function `produce':

course_design.c:32: parse error before "pthread_t"

course_design.c: In function `consume':

course_design.c:51: parse error before "pthread_t"

由于在produceconsume中都调用了display函数,本应该用display(id),但由于粗心使用display(pthread_t id)所以出现了上述错误提示。

 

也曾经在定义线程是把pthread_t写成,lpthread而出现以下提示错误

course_design.c:16: parse error before "id"

course_design.c: In function `produce':

course_design.c:32: `id' undeclared (first use in this function)

course_design.c:32: (Each undeclared identifier is reported only once

course_design.c:32: for each function it appears in.)

付出了不少的时间找出原因

以上都是些语法方面的问题,所以查错起来也比较方便。但更重要的是逻辑上的错误,它编译通过,能运行,但结果有问题。这往往是算法方面的问题。

这方面的问题出现在:

一,线程的互斥出现问题。如,sem_post(&sem);位置没放好,特别是当放到while(1)的循环外面是就会出现一次性的生产完。sem_wait(&sem);也回出现相类似的问题。

二,问题出现在in与out的控制上,如果考虑不完全很容易出现10个缓冲区只能利用其中的8个或者9个空间。当把程序调试成功本人发现以前犯的错误很幼稚,在加上当时出现的问题也是实在是太多了,一个小小的失误或者考虑不周都会失败,所以现在就不一一列举了。

把以上的问题解决,程序能够基本上正确运行,由于开始只创建了2个线程,所以运行的同步效果不是很好,在老师的提示下,我后来创建了8个线程,后来我终于理解了老师的意思,线程越多它们抢占系统的资源也就越激烈,所以会产生跟好的同步效果。

 

五,输出结果

buffer[7]=2

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519388

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

produce an item:the id of thread is 134519380

buffer[0]=1

buffer[1]=7

buffer[7]=8

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519384

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

produce an item:the id of thread is 134519380

buffer[0]=1

buffer[1]=7

buffer[7]=2

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519468

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

produce an item:the id of thread is 134519360

buffer[0]=1

buffer[1]=7

buffer[7]=5

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519388

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

produce an item:the id of thread is 134519360

buffer[0]=1

buffer[1]=7

buffer[7]=2

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519384

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

produce an item:the id of thread is 134519360

buffer[0]=1

buffer[1]=7

buffer[7]=8

buffer[8]=8

buffer[9]=5

in=7

out=7

consume an item:the id of thread is 134519392

buffer[0]=1

buffer[1]=7

buffer[8]=8

buffer[9]=5

in=7

out=7

[lc@Hawk course_design]$

   

 

六,源代码

 

  

/*本实验用信号量实现的,创建了两个线程,一个生产者线程,一个消费线程*/

 

#include"stdlib.h"

#include"pthread.h"

#include"semaphore.h"

#include"time.h"

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];  /*缓冲区*/

int in=0;/*输入指针,指向最后插入的数据*/

int out=0;/*输出指针,指向第一个插入的数据*/

pthread_t t1,t2,t3,t4,t5,t6,t7,t8;

sem_t sem;/*信号灯*/

 

 

void produce(pthread_t id)/*生产者函数,本程序通过循环队列直接实现对缓冲的完全使用*/

{

  int nextproduced;/*用于装插入数据的临时变量*/

  while(1)

  {

    nextproduced=random()%10+1;/*为了产生1-10的随机数,通过模10的方法*/

    while(((in+1)%BUFFER_SIZE)==out)/*判断是否还有插入的空间*/

       ;

    printf("/nproduce an item:");

    if(in==out&&buffer[in]==0)/*判断是否是缓冲没数据,此时的in指针不向后移*/

        buffer[in]=nextproduced;

    else                       /*否则in指针向后移一位*/     

    {      

     buffer[(in+1)%BUFFER_SIZE]=nextproduced;

     in=(in+1)%BUFFER_SIZE;

    }

    display(id);/*调用显示缓冲区的状态函数*/

    sem_post(&sem);/*增加一个资源*/  

   }     

}

void consume(pthread_t id)

{

  while(1)

  {

   sem_wait(&sem);/*减少一个资源*/

   printf("/nconsume an item:");/*显示线程的id号*/

   if(in==out&&buffer[out]!=0)/*判断in与out是否指向一个区,且不为空,此时out指针不移动*/

      buffer[out]=0;

   else                     /*否则,out指针向后移一位*/

   {      

    buffer[out]=0;    

    out=(out+1)%BUFFER_SIZE;

    }

   display(id);

  }

}

int  display(pthread_t id)

{

 int i;

 printf("the id of thread is %d",id);

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

 {

  if(buffer[i]!=0)/*本程序通过判断区中的数据是否为0来判断是否有数据*/

      printf("/nbuffer[%d]=%d",i,buffer[i]);

   }

printf("/nin=%d",in);

printf("/nout=%d",out);

}

int main(void)

{

 sem_init(&sem,0,0);/*初始化信号量*/

 pthread_create(&t1,NULL,(void *)produce,&t1);/*创建生产者线程*/

 pthread_create(&t2,NULL,(void *)consume,&t2);/*创建消费者线程*/

 pthread_create(&t3,NULL,(void *)produce,&t3);/*创建生产者线程*/

 pthread_create(&t4,NULL,(void *)consume,&t4);/*创建消费者线程*/

 pthread_create(&t5,NULL,(void *)produce,&t5);/*创建生产者线程*/

 pthread_create(&t6,NULL,(void *)consume,&t6);/*创建消费者线程*/

 pthread_create(&t7,NULL,(void *)produce,&t7);/*创建生产者线程*/

 pthread_create(&t8,NULL,(void *)consume,&t8);/*创建消费者线程*/

 pthread_join(t1,NULL);/*防止程序过早退出*/

}

 

七,总结

通过本次程序的准备,设计,调试与运行,本人学会了不少的知识。首先加深了我对线程与进程理解,消除了对多线程软件设计的神秘性。在准备与设计阶段出现不少的障碍,可能是做系统级别的程序比较少的缘故,除了老师附带的有关linux多线程的编程资料,我还在网上搜索了不少的资料,但最后还是用4.4信号灯实现的。对于缓冲区的完全的利用又考验了我对数据结构的理解,这里我用了循环队列的思想实现了。更重要的是问题是出现在调试阶段。上面第四点的调试报告只是其中的一部份,这里充分考验了我的c语言的基本功。最令人激动的是在自己与同学的帮助下,我的程序成功的运行了,虽然效果没有达到预想的。

0 0

相关博文

我的热门文章

img
取 消
img即使是一小步
也想与你分享
打开
img