您的位置:首页 > 其它

UNIX程序设计实验六 线程及其同步—哲学家问题

2012-06-16 21:04 337 查看
实验六 线程及其同步—哲学家问题

学习线程的编程和同步。
二 实验要求:
1、程序语法
philosopher_th <N> [ -t <time> ]
N是哲学家的个数(N >= 2)。time是哲学家进餐和沉思的持续时间值,缺省为2秒。
2、哲学家的编号为0 ~ N-1,分别用N个线程独立模拟。
3、程序的输出要简洁,例如,当编号为3的哲学家在进餐时,就打印:
philosopher 3 iseating
而当他在沉思时,则打印:
philosopher 3 isthinking
不要输出其他任何信息。
4、使用pthread的semaphore.h提供的信号量同步线程。
5、程序一直运行,直到人为地终止它(如按Ctrl-C或Ctrl-\)。不允许出现僵尸进程。
四实验程序

#include"apue.h"

#include<stdio.h>

#include<semaphore.h>

#include<pthread.h>

intmain(int argc,char * argv[])

{

unsigned int n,time;

int i;

if(argc==2)

{

n=(unsigned int)atoi(argv[1]);

time=2;

printf("** The default time is: %d **\n",time);

printf("** The number of philosopher is %d **\n",n);

}

elseif(argc==4&&(strcmp(argv[2],"-t"))==0)

{

n=(unsigned int)atoi(argv[1]);

time=(unsigned int)atoi(argv[3]);

printf("** The design time is:%d **\n",time);

printf("** The number of philosopher is %d **\n",n);

}

else

{

printf("Usage:./philosopher N -ttime\n");

}

pthread_t tid
;

sem_t sem
;

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

{ interr;

err=sem_init(&sem[i],0,1);

if(err!=0)

printf("semaphore[i] initfailed\n");

}

void thinking(int i,int time)

{

printf("philosopher %d is thinking \n",i);

sleep(time);

}

void eating(int i,int time)

{

printf("philosopher %d is eating \n",i);

sleep(time);

}

void takefork(int i)

{

if(i==n-1)

{

sem_wait(&sem[0]);

sem_wait(&sem[i]);

}

else

{

sem_wait(&sem[i]);

sem_wait(&sem[i+1]);

}

}

void putfork(int i)

{

if(i==n-1)

{

sem_post(&sem[0]);

sem_post(&sem[i]);

}

else

{

sem_post(&sem[i]);

sem_post(&sem[i+1]);

}

}

void *thr_fn(void * arg)

{

int i=(int) arg;

sleep(i);

while(1)

{

thinking(i,time);

takefork(i);

eating(i,time);

putfork(i);

}

}

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

{

int err;

err=pthread_create(&tid[i],NULL,thr_fn,(void*)i);

if(err!=0)

printf("can't create thread%d:%s\n",i,strerror(err));

}

while(1)

pause;

}

四实验结果

源程序名:thread_philosopher.c

可执行程序名:thph

编译方法:gccthread_philosopher.c error2e.c –o thph -lpthread

结束方法:ctrl+c

运行过程:

1.编译





2.实现第一种情况:(自己定义哲学家的个数,并且使用默认时间值)

例如:./thph 5






3.实现第二种情况:(自己定义哲学家个数和使用时间值)

例如:./thph 5 -t 3






五 实验小结

通过本次实验,可以学到:信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern intsem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  
函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  
函数sem_destroy(sem_t *sem)用来释放信号量sem。 
信号量用sem_init函数创建的,下面是它的说明:

  #include<semaphore.h>

int sem_init (sem_t *sem, intpshared, unsigned int value);

这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。 (这个参数受版本影响), pshared传递一个非零将会使函数调用失败。

  这两个函数控制着信号量的值,它们的定义如下所示:

  

  #include <semaphore.h>

int sem_wait(sem_t * sem);

int sem_post(sem_t * sem);

这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。

sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。

sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: