(一) 实验目的
深刻理解线程和进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标
(二) 实验内容
以Linux系统进程和线程机制为背景,掌握fork()和clone()系统调用的形式和功能,以及与其相适应的高级通讯方式。由fork派生的子进程之间通过pipe通讯,由clone创建的线程之间通过共享内存通讯,对于后者需要考虑互斥问题。
以生产者/消费者问题为例,通过实验理解fork()和clone()两个系统调用的区别。程序要求能够创建4个进程或线程,其中包括两个生产者和两个消费者,生产者和消费者之间能够传递数据。
(三) 实验准备
fork系统调用
clone系统调用
pipe系统调用
sem_wait(&s)和sem_post(&s)
pthread_mutex_lock(&mutex)和pthread_mutex_unlock(&mutex)
(四) 实验设计
用pipe()创建一个管道文件,然后用fork()创建两个生产进程和两个消费进程,它们之间通过pipe()传递信息。
用clone()创建四个轻进程(线程),用参数指明共享内存等资源,通过共享内存模拟生产消费问题,利用pthread_mutex_lock(), pthread_mutex_unlock()等函数实现对共享存储区访问的互斥。
实验代码:
fork系统调用实验代码:
#include "sys/types.h"
#include "sys/file.h"
#include "unistd.h"
char r_buf[4]; //读缓冲
char w_buf[4]; //写缓冲
int pipe_fd[2];
pid_t pid1, pid2, pid3, pid4;
int producer(int id);
int consumer(int id);
int main(int argc,char **argv)
{
if(pipe(pipe_fd)<0)
{
printf("pipe create error \n");
exit(-1);
}
else
{
printf("pipe is created successfully!\n");
if((pid1=fork())==0)
producer(1);
if((pid2=fork())==0)
producer(2);
if((pid3=fork())==0)
consumer(1);
if((pid4=fork())==0)
consumer(2);
}
close(pipe_fd[0]); //需要加上这两句
close(pipe_fd[1]); //否这会有读者或者写者永远等待
int i,pid,status;
for(i=0;i<4;i++)
pid=wait(&status);
exit(0);
}
int producer(int id)
{
printf("producer %d is running!\n",id);
close(pipe_fd[0]);
int i=0;
for(i=1;i<10;i++)
{
sleep(3);
if(id==1) //生产者1
strcpy(w_buf,"aaa\0");
else //生产者2
strcpy(w_buf,"bbb\0");
if(write(pipe_fd[1],w_buf,4)==-1)
printf("write to pipe error\n");
}
close(pipe_fd[1]);
printf("producer %d is over!\n",id);
exit(id);
}
int consumer(int id)
{
close(pipe_fd[1]);
printf("producer %d is running!\n",id);
if (id==1) //消费者1
strcpy(w_buf,"ccc\0");
else //消费者2
strcpy(w_buf,"ddd\0");
while(1)
{
sleep(1);
strcpy(r_buf,"eee\0");
if(read(pipe_fd[0],r_buf,4)==0)
break;
printf("consumer %d get %s, while the w_buf is %s\n",id,r_buf,w_buf);
}
close(pipe_fd[0]);
printf("consumer %d is over!\n", id);
exit(id);
}
编译:gcc fork.c -o fork.out
源文件:fork.c
运行:./fork.out
编译后生成文件:fork.out
结果:
#include "sched.h"
#include "pthread.h"
#include "stdio.h"
#include "stdlib.h"
#include "semaphore.h"
int producer(void * args);
int consumer(void *args);
pthread_mutex_t mutex;
sem_t product;
sem_t warehouse;
char buffer[8][4];
int bp=0;
main(int argc,char** argv)
{
pthread_mutex_init(&mutex,NULL);
sem_init(&product,0,0);
sem_init(&warehouse,0,8);
int clone_flag,arg,retval;
char *stack;
clone_flag=CLONE_VM|CLONE_SIGHAND|CLONE_FS| CLONE_FILES;
int i;
for(i=0;i<2;i++)
{ //创建四个线程
arg = i;
stack =(char*)malloc(4096);
retval=clone((void*)producer,&(stack[4095]),clone_flag, (void*)&arg);
stack =(char*)malloc(4096);
retval=clone((void*)consumer,&(stack[4095]),clone_flag, (void*)&arg);
//usleep(1000);
usleep(1);
}
exit(1);
}
int producer(void* args)
{
int id = *((int*)args);
int i;
for(i=0;i<10;i++)
{
sleep(i+1); //表现线程速度差别
sem_wait(&warehouse);
pthread_mutex_lock(&mutex);
if(id==0)
strcpy(buffer[bp],"aaa\0");
else
strcpy(buffer[bp],"bbb\0");
bp++;
printf("producer%d produce %s in %d\n",id,buffer[bp-1],bp-1);
pthread_mutex_unlock(&mutex);
sem_post(&product);
}
printf("producer%d is over!\n",id);
}
int consumer(void *args)
{
int id = *((int*)args);
int i;
for(i=0;i<10;i++)
{
sleep(10-i); //表现线程速度差别
sem_wait(&product);
pthread_mutex_lock(&mutex);
bp--;
printf("consumer%d get %s in %d\n",id,buffer[bp],bp+1);
strcpy(buffer[bp],"zzz\0");
pthread_mutex_unlock(&mutex);
sem_post(&warehouse);
}
printf("consumer%d is over!\n",id);
}
编译:gcc pthread clone.c -o clone.out
源文件clone.c
运行:./clone.out
编译后文件:clone.out
结果:(太长只截部分)