实验二
进入VI编辑器 格式:vi 文件名 例 :vi sy.c
Vi编辑器三种工作方式:
1.编辑方式:进入VI 处于编辑方式
2.文本输入方式:在编辑方式下输入a ,进入追加方式,输入i,进入插入方式 3. 命令方式:在输入方式下,按Esc 键,由文本输入转向编辑方式,输入冒号:进入命令方式 4.退出vi : wq写文件退出
:w wenjianming 写文件 : q! 不写退出 :wq! 写退出 编译c文件
Gcc -o wenjianming.out wenjianming.c 运行文件:
./wenjianming.out
1. 实验内容和目的
用vi编辑器编辑下列文件,使用gcc编译器和gdb调试器,对下列程序编译运行,分析运行结果。要求至少完成3个程序。 2.程序示例
(1) /* 父子进程之间的同步之例 */ #include
int pid1;
if(pid1=fork()) /*create child1 */
{ if (fork()) /*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*/
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); } } }
分析: 上述程序是父进程首先创建一个子进程,若成功,再创建另一个子进程,之后三个进程并发执行。究竟谁先执行,是随机的,可根据执行结果判断。试分析该程序的所有运行结果。
注释: fork( ) 调用正确完成时,给父进程返回地是被创建子进程的标识,给子进程返回的是0;创建失败时,返回给父进程的时-1; exit(0) 进程终止自己
wait(0) 父进程同步等待子进程结束,即无子进程结束,父进程等待。 (2)管道通信机制
通过使用管道实现两个和多个进程之间的通信。所谓管道,就是将一个进程的标准输出与另一个进程的标准输入联系在一起,进行通信的一种方法。同组进程之间可用无名管道进行通信,不同组进程可通过有名管道通信。
使用无名管道进行父子进程之间的通信 #include
char parent[]=”a message to pipe’ communication.\\n”; main()
{ int pid,chan1[2]; char buf[100]; pipe(chan1); pid=fork(); 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],parent,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”); } }
观察运行结果。
注释:pipe( int filedes[2]):创建一个无名管道,filedes[0]为读通道,filedes[1]为写通道。 (3)Linux中的多线程编程threads.c #include
pthread_t thread[2]; pthread_mutex_t mut; int number=0, i;
void *thread1() {
printf (\
for (i = 0; i < MAX; i++) {
printf(\ pthread_mutex_lock(&mut); number++;
pthread_mutex_unlock(&mut); sleep(2); }
printf(\主函数在等我完成任务吗?\\n\ pthread_exit(NULL); }
void *thread2() {
printf(\
for (i = 0; i < MAX; i++)
{
printf(\ pthread_mutex_lock(&mut); number++;
pthread_mutex_unlock(&mut); sleep(3); }
printf(\主函数在等我完成任务吗?\\n\ pthread_exit(NULL); }
void thread_create(void) {
int temp;
memset(&thread, 0, sizeof(thread)); //comment1 /*创建线程*/
if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) //comment2
printf(\线程1创建失败!\\n\ else
printf(\线程1被创建\\n\
if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
printf(\线程2创建失败\ else
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; }
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。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。 3)pthread_join pthread_exit
函数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,