logo资料库

操作系统文件管理实验报告.docx

第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
资料共9页,剩余部分请下载后查看
else
else { if(pid1==0)/* child1 */ //当并发执行
exit(0) 进程终止自己
else{
/*创建线程*/
实验二 进入 VI 编辑器 sy.c 格式:vi 文件名 例 :vi Vi 编辑器三种工作方式: 1. 编辑方式:进入 VI 处于编辑方式 2. 文本输入方式:在编辑方式下输入 a ,进入追加方式,输入 i,进入插入方式 3. 命令方式:在输入方式下,按 Esc 键,由文本输入转向编辑方式,输入冒 号:进入命令方式 4. 退出 vi : wq 写文件退出 :w wenjianming 写文件 : q! 不写退出 :wq! 写退出 -o wenjianming.out wenjianming.c 编译 c 文件 Gcc 运行文件: ./wenjianming.out 1. 实验内容和目的 用 vi 编辑器编辑下列文件,使用 gcc 编译器和 gdb 调试器,对下列程序编译运行,分析 运行结果。要求至少完成 3 个程序。 2.程序示例 (1) /* 父子进程之间的同步之例 */ #include main( ) { int pid1; if(pid1=fork()) if (fork()) { /*create child1 */ /*create the child2*/ //此时启动一个父进程 {printf (“parent’s context.\n”); printf(“parent is waiting the child1 terminate.\n); wait(0); //父进程进入等待状态 printf(“parent is waiting the child2 terminate.\n”); wait(0); printf(“parent terminate.\n”); exit(0); //进程终止 } else /* child2*/
//进入 5s 休眠状态 //当并发执行子程序 1 时 printf(“child2’s context.\n”); sleep(5); printf(“ child2 terminate.\n”); exit(0); } else { if(pid1==0)/* child1 */ { printf(“child1’s context.\n”); sleep(10); printf(“child1 terminate.\n”); exit(0); } } } 分析: 启动父进程后,开始创建子进程。若第一个子进程 1 创建成功,则继续创建子进程 2,接下 来进入三段程序并发执行的状态。结合我的运行结果来看,子进程 1 先被执行打印“child1’s context.\n”然后子进程 1 进入 10 秒睡眠状态;随机轮到子进程 2 执行打印“child2’s context.\n” 然后子进程 2 进入 5 秒睡眠状态;由于子进程 1 睡眠时间较长,接下来轮到父进程执行 printf (“parent’s context.\n”);和 printf(“parent is waiting the child1 terminate.\n);然后等待子进程响 应,由于子进程 2 睡眠时间较短,接下来先执行子进程 2 printf(“ child2 terminate.\n”),子进 程 2 结束。此时随机选择了执行父进程(可能子进程 1 还没醒)printf(“parent is waiting the child2 terminate.\n”),等待子进程 1,子进程 1 醒后执行 printf(“child1 terminate.\n”);子进程 1 结束。父进程执行 printf(“parent terminate.\n”);整个进程终止。 注释: fork( ) 调用正确完成时,给父进程返回地是被创建子进程的标识,给子进程返回的 是 0;创建失败时,返回给父进程的时-1; exit(0) 进程终止自己 wait(0) 父进程同步等待子进程结束,即无子进程结束,父进程等待。
(2)管道通信机制 通过使用管道实现两个和多个进程之间的通信。所谓管道,就是将一个进程的标准输 出与另一个进程的标准输入联系在一起,进行通信的一种方法。同组进程之间可用无名管道 进行通信,不同组进程可通过有名管道通信。 使用无名管道进行父子进程之间的通信 #include #include #include int pipe( int filedes[2]); char parent[]=”a message to pipe’ communication.\n”; main() { int pid,chan1[2]; char buf[100]; pipe(chan1); pid=fork(); //创建管道 //创建容量为 100 的缓存 if(pid<0) { printf(“to create child error\n”); exit(1); } if(pid>0) //表示在父进程中,开启写通道
{ close(chan1[0]); printf(“parent process sends a message to child.\n”); write(chan1[1],parenit,sizeof(parent)); /*父进程关闭读通道*/ //括号中定义要进行读写操作的文件描述 符,内存地址,字节数 close(chan1[1]); printf(“parent process waits the child to terminate.\n”); wait(0); printf(“parent process terminates.\n”); //关闭写通道 } else{ close(chan1[1]);/*子进程关闭写通道*/ read(chan1[0],buf,100); printf(“the message read by child process form parent is %s.\n”,buf); close (chan1[0]); printf(“child process terminates\n”); //读文件至 100 字节 } } 观察运行结果。 注释:pipe( int filedes[2]):创建一个无名管道,filedes[0]为读通道,filedes[1]为写通道。 分析:创建通道后,父进程关闭读通道以避免子进程读数据,开启写通道将数据写入 文件;写完后子进程同样关闭写通道以避免父进程写数据,再开启读通道读出数据。
(3)Linux 中的多线程编程 threads.c #include #include #include #include #define MAX 10 // 两个线程共同运行 10 次 pthread_t thread[2]; pthread_mutex_t mut; int number=0, i; void *thread1() { printf ("thread1 : I'm thread 1\n"); for (i = 0; i < MAX; i++) { printf("thread1 : number = %d\n",number); pthread_mutex_lock(&mut); number++; pthread_mutex_unlock(&mut); sleep(2); } printf("thread1 :主函数在等我完成任务吗?\n"); pthread_exit(NULL); //退出线程 } void *thread2() { printf("thread2 : I'm thread 2\n"); for (i = 0; i < MAX; i++) { //for 循环至 i 加到最大值 printf("thread2 : number = %d\n",number); pthread_mutex_lock(&mut); //上互斥锁 number++; pthread_mutex_unlock(&mut); sleep(3); } //解除互斥锁 printf("thread2 :主函数在等我完成任务吗?\n"); pthread_exit(NULL); }
void thread_create(void) { int temp; memset(&thread, 0, sizeof(thread)); /*创建线程*/ if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment1 //comment2 else printf("线程 1 创建失败!\n"); printf("线程 1 被创建\n"); if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3 else } printf("线程 2 创建失败"); printf("线程 2 被创建\n"); void thread_wait(void) { /*等待线程结束*/ if(thread[0] !=0) { //comment4 pthread_join(thread[0],NULL); printf("线程 1 已经结束\n"); } if(thread[1] !=0) { //comment5 pthread_join(thread[1],NULL); printf("线程 2 已经结束\n"); } } int main() { /*用默认属性初始化互斥锁*/ pthread_mutex_init(&mut,NULL); printf("我是主函数哦,我正在创建线程,呵呵\n"); thread_create(); printf("我是主函数哦,我正在等待线程完成任务阿,呵呵\n"); thread_wait(); return 0; }
分析:创建两个线程,让他们交替互斥的完成 1 到 10 为止的计数操作,当线程 1 计数时, 添加互斥锁避免线程而运算,运算完毕后交由进程而互斥完成下一个数的累加运算,线程 1 和 2 就这样交替进行。 3. 注意:Gcc –lpthread –o thread.out thread.c 线程相关操作 1) pthread_t pthread_t 在头文件/usr/include/bits/pthreadtypes.h 中定义: typedef unsigned long int pthread_t; 它是一个线程的标识符。 2)pthread_create 函数 pthread_create 用来创建一个线程,它的原型为: extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr, void *(*__start_routine) (void *), void *__arg)); 第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是 线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数 thread 不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生 成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时, 函数返回 0,若不为0 则说明创建线程失败,常见的错误返回代码为EAGAIN 和 EINVAL。 前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线 程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原 来的线程则继续运行下一行代码。
pthread_exit 3)pthread_join 函数 pthread_join 用来等待一个线程的结束。函数原型为: extern int pthread_join __P ((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存 储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到 被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有 两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另 一种方式是通过函数 pthread_exit 来实现。它的函数原型为: extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__)); 唯一的参数是函数的返回代码,只要 pthread_join 中的第二个参数 thread_return 不是 NULL,这个值将被传递给 thread_return。最后要说明的是,一个线程不能被多个线程 等待,否则第一个接收到信号的线程成功返回,其余调用 pthread_join 的线程则返回错 误代码 ESRCH。 在这一节里,我们编写了一个最简单的线程,并掌握了最常用的三个函数 pthread_create, pthread_join 和 pthread_exit。下面,我们来了解线程的一些常用属性以及如何设置这些 属性。 互斥锁相关 互斥锁用来保证一段时间内只有一个线程在执行一段代码。 1) pthread_mutex_init pthread_mutex_unlock 函数 pthread_mutex_init 用来生成一个互斥锁。NULL 参数表明使用默认属性。如果 需 要 声 明 特 定 属 性 的 互 斥 锁 , 须 调 用 函 数 pthread_mutexattr_init 。 函 数 pthread_mutexattr_setpshared 和函数 pthread_mutexattr_settype 用来设置互斥锁属性。前 一 个 函 数 设 置 属 性 pshared , 它 有 两 个 取 值 , PTHREAD_PROCESS_PRIVATE 和 PTHREAD_PROCESS_SHARED。前者用来不同进程中的线程同步,后者用于同步本进 程 的 不 同 线 程 。 在 上 面 的 例 子 中 , 我 们 使 用 的 是 默 认 属 性 PTHREAD_PROCESS_ PRIVATE。后者用来设置互斥锁类型,可选的类型有 PTHREAD_MUTEX_NORMAL、 PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE 和 PTHREAD _MUTEX_DEFAULT。它们分别定义了不同的上锁、解锁机制,一般情况下,选用最后 一个默认属性。 2) pthread_mutex_lock pthread_mutex_lock 声明开始用互斥锁上锁,此后的代码直至调用 pthread_mutex_unlock 为 止 , 均 被 上 锁 , 即 同 一 时 间 只 能 被 一 个 线 程 调 用 执 行 。 当 一 个 线 程 执 行 到 pthread_mutex_lock 处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序 将等待到另一个线程释放此互斥锁。 注意: 1)需要说明的是,上面的两处 sleep 不光是为了演示的需要,也是为了让线程睡眠一段 时间,让线程释放互斥锁,等待另一个线程使用此锁。 2)请千万要注意里头的注释 comment1-5,如果没有 comment1 和 comment4,comment5, 将导致在 pthread_join 的时候出现段错误,另外,上面的 comment2 和 comment3 是根源 所在,所以千万要记得写全代码。因为上面的线程可能没有创建成功,导致下面不可能 等到那个线程结束,而在用 pthread_join 的时候出现段错误(访问了未知的内存区)。 另外,在使用 memset 的时候,需要包含 string.h 头文件。 实验报告 (1) 实验题目。 pthread_delay_np
分享到:
收藏