一、实验目的

学习使用Linux的系统调用和pthread线程库编写程序,进一步理解、掌握操作系统进程、线程概念,利用信号量解决进程同步与互斥

二、实验内容

1.         Fibonacci序列是0, 1, 1, 2, 3, 5, 8, .... ,通常它可以表示为:

f ib0 = 0

f ib1 = 1

f ibn = f ibn1 + f ibn2

编写一个C程序,使用系统调用fork()创建两个子进程P1P2。他们的任务如下:

1)        子进程P1打印自己的pid,然后使用exec(族)系统调用显示当前目录下文件和子目录的详细信息。

2)        子进程P2中生成Fibonacci序列,序列的个数在程序命令行中作为参数传入,例如,参数为7,则子进程P2生成的Fibonacci序列为01235813。通过某种进程通信机制(共享内存、管道、消息等IPC机制),子进程P2把生成的Fibonacci序列发送给父进程,并由父进程输出(打印)Fibonacci序列。在父子进程通信的过程中必须实现同步,以使在子进程完成生成序列之前,父进程不会输出Fibonacci序列。使用wait()系统调用可以实现各进程的同步。执行必要的错误检查以保证不会接受命令行参数传递来的负值。

 

2.         编写程序实现生产者-消费者问题。使用linuxPthread线程库,创建2个生产者线程和2个消费者线程。生产者线程计算当前的时间,把时间、第几次计算时间的序号(循环次数)和线程ID作为一个消息,把消息放入缓冲区,消费者线程从缓冲区读出一个消息并显示消息。缓冲区大小为5个,每个生产者线程生产10个消息,每个消费者线程消费10个消息,即生产和消费分别为20次。

  生产者及消费者线程之间需要实现同步和互斥,Pthread线程库的信号量机制可以完成这一任务。

 

三、源代码

(1)

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
//定义管道的最大值
#define MAXLINE 80


//覅波那次函数
int fibonaci(int n)
{
    if(n==0) return 0;
    else if(n==1) return 1;
    else
        return fibonaci(n-2)+fibonaci(n-1);
}

//main主函数
void main(int argc,char* argv[])
{
    pid_t pid1; //子进程p1的id
    pid_t pid2; //子进程p2的id
    int fd[2];
    int k=0;
    int line[MAXLINE];
    for(k;k<MAXLINE;k++)
        line[k]=-1;
    pipe(fd);

    pid1=fork();
    if(pid1<0)
    {
        printf("error fork\n");
        exit(1);
    }
    else if(pid1==0) //子进程1
    {
        //显示当前目录的文件信息
        printf("The current content is as follows:\n");
        execlp("/bin/ls","ls",NULL);
    }
    else //父进程
    {
        //继续产生子进程2
        pid2=fork();
        if(pid2<0)
        {
            printf("error fork\n");
            exit(0);
        }
        else if(pid2==0) //子进程2
        {
            int number=atoi(argv[1]); //通过命令行参数得到斐波那契数组的参数
            if(number<0)number=-number; //error correct
            //调用fibonaci函数
            while(number>=1)
            {
                line[number]=fibonaci(number-1);
                number=number-1;
            }
            //把数组写入到管道
            close(fd[0]);
            write(fd[1],line,MAXLINE);
        }
        else
        {
            wait(NULL); //wait for pid1
            wait(NULL); //wait for pid2
            close(fd[1]);
            read(fd[0],line,MAXLINE);
            printf("The fibonaci array is as follows:\n ");
            int m=1;
            while(line[m]!=-1)
            {           
                printf("%d ",line[m]);
                m=m+1;
            }
            printf("\n");
        }
    }
    close(fd[0]);
    close(fd[1]);
    //return 0;
}


   
(2)

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <time.h>
#include <malloc.h>
#include <stdlib.h>

sem_t sem1,sem2; //信号量   
pthread_mutex_t mutex1,mutex2; //互斥量

//定义缓冲区结构
struct container_buffer
{
    //线程号
    pid_t id;
    //读取序号
    int number;
    //时间
    time_t mytime;
}*p,*r,*w; //定义3个结构指针



/*函数write1,2,用于生产者计算当前的时间,把时间、第几次计算时间的序号
(循环次数)和线程ID作为一个消息,把消息放入缓冲区
*/
void *write1(void *arg)
{
    //生产10个消息
    int i=1;
    for(i;i<=10;i++)
    {
        //if(w==p+5)w=p;
        sem_wait(&sem1); //缓冲减1
        pthread_mutex_lock(&mutex1); //加锁

        w->number=i;
        w->id=pthread_self();
        time(&(w->mytime));
        w++;

        sem_post(&sem2); //可读加1
        pthread_mutex_unlock(&mutex1); //解锁
        sleep(1+(int)(5*rand()/(RAND_MAX+1.0))); //随机睡觉x秒,1<=x<=5
    }   
}

void *write2(void *arg)
{
    //生产10个消息
    int j=1;
    for(j;j<=10;j++)
    {
        //if(w==p+5)w=p;
        sem_wait(&sem1);
        pthread_mutex_lock(&mutex1);

        w->number=j;
        w->id=pthread_self();
        time(&(w->mytime));
        w++;

        sem_post(&sem2);
        pthread_mutex_unlock(&mutex1);
        sleep(1+(int)(5*rand()/(RAND_MAX+1.0)));
    }
}
/*函数read1,2,用于消费者从缓冲区读出一个消息并显示消息
*/
void *read1(void *arg)
{
    //消费10个消息
    int k=1;
    for(k;k<=10;k++)
    {
        //if(r==p+5)r=p;
        sem_wait(&sem2); //可读减1
        pthread_mutex_lock(&mutex2); //加锁
        printf("消费者1第%d次读取消息---, id=%u, time is: %s\n",r->number,(unsigned)(r->id),ctime(&(r->mytime)));
        r++;
        sem_post(&sem1); //缓冲加1
        pthread_mutex_unlock(&mutex2); //解锁
        sleep(1+(int)(5*rand()/(RAND_MAX+1.0))); ////随机睡觉x秒,1<=x<=5
    }
}

void *read2(void *arg)
{
    //消费10个消息
    int l=1;
    for(l;l<=10;l++)
    {
        //if(r==p+5)r=p;
        sem_wait(&sem2);
        pthread_mutex_lock(&mutex2);
        printf("消费者2第%d次读取消息---, id=%u, time is: %s\n",r->number,(unsigned)(r->id),ctime(&(r->mytime)));
        r++;
        sem_post(&sem1);
        pthread_mutex_unlock(&mutex2);
        sleep(1+(int)(5*rand()/(RAND_MAX+1.0)));
    }
}

void main()
{
    pthread_t pro1,pro2;//生产者
    pthread_t cum1,cum2;//消费者

   
    sem_init(&sem1,0,5); //创建初始值为5的信号量
    sem_init(&sem2,0,0); //创建初始值为0的信号量

    pthread_mutex_init(&mutex1,NULL);
    pthread_mutex_init(&mutex2,NULL);

    p=(struct container_buffer*)malloc(20*sizeof(struct container_buffer));    //申请20个结构内存空间
    r=p;
    w=p;

    //创建2个生产者线程和2个消费者线程
    pthread_create(&pro1,NULL,write1,NULL);
    pthread_create(&pro2,NULL,write2,NULL);
    pthread_create(&cum1,NULL,read1,NULL);
    pthread_create(&cum2,NULL,read2,NULL);

    //互斥量销毁
    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);

    //线程挂起
    pthread_join(pro1,NULL);
    pthread_join(pro2,NULL);
    pthread_join(cum1,NULL);
    pthread_join(cum2,NULL);
   
    //释放内存
    free(p);
    return;
}