zoukankan      html  css  js  c++  java
  • 基础操作系统-进程-并发程序设计

    这学期感觉最有难度的就是操作系统这门课了,以前Linux接触的不多,双学位跳级学习课程暂时还没有学完其中的基础课。所以可能错误多一些。

    1、  相关头文件

    <unistd.h> <sys/types.h> <sys/wait.h> <stdio.h> <stdlib.h>

    2、  函数说明

    l  fork(建立一个新的进程)

    定义函数  pid_t fork(void);

    函数说明  fork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码,组代码,环境变量、已打开的文件代码、工作目录和资源限制等。

    返回值    如果fork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0。如果fork 失败则直接返回-1,失败原因存于errno中。

    l  waitpid(等待子进程中断或结束)

    定义函数  pid_t waitpid(pid_t pid,int * status,int options);

    函数调用  waitpid(pid, NULL, 0);

    函数说明  waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。参数pid为欲等待的子进程识别码,其他数值意义如下:

    pid<-1 等待进程组识别码为pid绝对值的任何子进程。

    pid=-1 等待任何子进程,相当于wait()。

    pid=0 等待进程组识别码与目前进程相同的任何子进程。

    pid>0 等待任何子进程识别码为pid的子进程。

    返回值  如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno

    l  getpid(取得进程识别码) 

    定义函数  pid_t getpid(void);

    函数说明  getpid()用来取得目前进程的进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。

    返回值    目前进程的进程识别码

    l  exit(正常结束进程) 

    定义函数  void exit(int status);

    函数说明  exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。

    l  execl(执行文件)

    定义函数  int execl(const char * path,const char * arg,....);

    函数说明  execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。

    返回值    如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。

    调用ls命令范例: execl("/bin/ls", "/bin/ls",  "-l" , "/etc", NULL);

     安装VMware Workstation Pro,下载Fedora Linux镜像文件,安装成功后如下图。打开终端,输入命令su进入管理员账户,输入yum install gcc 安装gcc编译器,测试编译环境正常

    单个子进程的创建分析:通过gcc first.c进行编译,在.a/.out执行输出,例程刚开始输出父进程pid 2218

    #include<unistd.h>

    #include<stdarg.h>

    #include<time.h>

    #include<sys/types.h>

    #include<sys/wait.h>

    #include<stdio.h>

    #include<stdlib.h>

    int tprintf (const char*fmt, ...);

    int main(void)

    {

           int i=0 ,j=0;

           pid_t pid;

           printf("Hello from Parent Process, PID is %d. ", getpid());

    1. fork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码,组代码,环境变量、已打开的文件代码、工作目录和资源限制等。因为父与子进程的pid值不一样,可以分别对父进程和子进程做操作,当pid为0时可以对子进程做操作,当pid>0时对父进程做操作,当pid为-1时创建进程失败输出提示信息;

           pid = fork();

           if(pid == 0) //child process

           {

                  sleep(1);

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

                  {

                         printf("Hello from Child Process %d. %d times ", getpid(), i+1);

                         sleep(1);

                  }

           }

           else if(pid != -1) //parent process

           {

                  tprintf("Parent forked one child process--%d. ",pid);

                  tprintf("Parent is waiting for child to exit. ");

                  waitpid(pid,NULL,0);

                  tprintf("Child Process has exited. ");

                  tprintf("Parent had exited. ");

           }

           else

           {

                  tprintf("Everything was done without error. ");

           }

           return 0;

    }

    waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status可以设成NULL。

    int tprintf(const char*fmt, ...)

    {

           va_list args;

           struct tm *tstruct;

           time_t tsec;

           tsec = time(NULL);

           tstruct = localtime(&tsec);

           printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

           va_start(args,fmt);

           return vprintf(fmt,args);

    }

    当pid=-1时创建进程失败输出错误时间、PID等错误信息。最后运行结果如下:

     

    在子进程中调用外部命令

    #include<unistd.h>

    #include<stdarg.h>

    #include<time.h>

    #include<sys/types.h>

    #include<sys/wait.h>

    #include<stdio.h>

    #include<stdlib.h>

    int tprintf (const char*fmt, ...);

    int main(void)

    {

           pid_t pid;

           pid = fork();

           if(pid == 0) //child process

           {

                  sleep(5);

                  tprintf("Hello from Child Process! ");

                  tprintf("I am calling exec. ");

                  execl("/bin/ps","-a",NULL);

                  tprintf("You should never see this because the child is already gone. ");

           }

    int execl(const char * path,const char * arg,....)用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中;

           else if(pid != -1) //parent process

           {

                  tprintf("Hello from Parent,pid %d. ", getpid());

                  sleep(1);

                  tprintf("Parent forked process %d. ",pid);

                  sleep(1);

                  tprintf("Parent is waiting for child to exit. ");

                  waitpid(pid,NULL,0);

                  tprintf("Parent had exited. ");

           }

    sleep是让线程指定休眠时间,然后继续工作  wait则是等待,直到有线程通知notify()唤醒他才会重新工作;

           else

           {

                  tprintf("Everything was done without error. ");

           }

           return 0;

    }

    int tprintf(const char*fmt, ...)

    {

           va_list args;

           struct tm *tstruct;

           time_t tsec;

           tsec = time(NULL);

           tstruct = localtime(&tsec);

           printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

           va_start(args,fmt);

           return vprintf(fmt,args);

    }

     

    编写一段程序实现以下功能:

    使用系统调用fork()创建两个子进程

    各个子进程显示和输出一些提示信息和自己的进程标识符。

    父进程显示自己的进程ID和一些提示信息,然后调用waitpid()等待多个子进程结束,并在子进程结束后显示输出提示信息表示程序结束。

    #include<unistd.h>

    #include <stdarg.h>

    #include <time.h>

    #include <sys/types.h>

    #include <sys/wait.h>

    #include <stdio.h>

    #include <stdlib.h>

    int tprintf(const char*fmt,...);

    int main()

    {

           int i=0,j=0;

           pid_t pid1;

           pid_t pid2;

           printf("Hello from Parent Process,PID is %d. ",getpid());

           pid1 = fork();

           if(pid1 == 0)

           {

                  sleep(1);

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

           {

              printf("Hello from Child Process one %d. %d times ",getpid(),i+1);

              sleep(1);

           }

           }

           else if(pid1 !=-1)

           {

                  tprintf("Part forked one child process--%d. ",pid1);

                  tprintf("Parent is waiting for child to exit. ");

                  waitpid(pid1,NULL,0);

                  pid2 = fork();

                  if(pid2 == 0)

                  {

                         sleep(1);

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

                         {

                                printf("Hello from Child Process two %d. %d times ",getpid(),i+1);

                                sleep(1);

                         }

                  }

                  else if(pid2 !=-1)

                  {

                         tprintf("Part forked one child process--%d. ",pid2);

                         tprintf("Parent is waiting for child to exit. ");

                         waitpid(pid2,NULL,0);

                         tprintf("Child Process has exited. ");

                         tprintf("Parent had exited. ");

                  }      

           }

           else  tprintf("Everything was done without error. ");  

           return 0;

    }

    int tprintf(const char*fmt,...)

    {

           va_list args;

           struct tm *tstruct;

           time_t tsec;

           tsec = time(NULL);

           tstruct = localtime (&tsec);

           printf("%02d:%02d:%02d:%5d",tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec,

           getpid());

           va_start(args,fmt);  

           return vprintf(fmt,args);

    }

    通过父进程创建一个子进程,运行一个子进程,再创建一个子进程,再运行一个子进程的方式,输出各个进程的标识码,可以得到正确的结果。而当两个子进程同时fork()时,会产生3个子进程,这是应为2个fork()放在一起时,会多fork()一个子进程。

     创建多个(3个以上)进程并发运行,控制好各个子进程输出自己的进程标识符和一些提示信息

    #include<unistd.h>

    #include<stdarg.h>

    #include<time.h>

    #include<sys/types.h>

    #include<sys/wait.h>

    #include<stdio.h>

    #include<stdlib.h>

    int tprintf (const char*fmt, ...);

    int main(void)

    {

           int i=0 ,j=0;

           pid_t pid,pid1,pid2;

           printf("Hello from Parent Process, PID is %d. ", getpid());

           pid = fork();//fork1

           if(pid == 0) //child process 1

           {

                  sleep(1);

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

                  {

                         printf("Hello from Child Process 11111 %d. %d times ", getpid(), i+1);

                         sleep(5);

                  }

           }

           else if(pid != -1) //parent process

           {

                  tprintf("Parent forked 111 child process--%d. ",pid);

                    pid1 = fork();//fork2

                    if(pid1 == 0) //child process 2

                     {

                         sleep(1);

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

                            {

                                  printf("Hello from Child Process 22222 %d. %d times ", getpid(), i+1);

                                  sleep(5);

                            }

                     }

                     else if(pid1 != -1) //parent process

                     {

                         tprintf("Parent forked 222 child process--%d. ",pid);

                                       

                         pid2 = fork();//fork3

                         if(pid2 == 0) //child process 3

                         {

                               sleep(1);

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

                               {

                                      printf("Hello from Child Process 33333 %d. %d times ", getpid(), i+1);

                                      sleep(5);

                               }

                          }

                          else if(pid2 != -1) //parent process

                          {

                                tprintf("Parent forked 333 child process--%d. ",pid);

                             //wait for children

                             pid_t temp_p;

                             while((temp_p = waitpid(-1, NULL, 0)) > 0)

                             {

                                tprintf("child had exited %d ",temp_p);

                             }

                                tprintf("Parent had exited. ");

                          }

                          else

                          {

                               tprintf("3333 Everything was done without error. ");

                          }

                     }

                     else

                     {

                          tprintf("2222 Everything was done without error. ");

                     }

           }

           else

           {

                  tprintf("1111 Everything was done without error. ");

           }

               

           return 0;

    }

    int tprintf(const char*fmt, ...)

    {

           va_list args;

           struct tm *tstruct;

           time_t tsec;

           tsec = time(NULL);

           tstruct = localtime(&tsec);

           printf("%02d:%02d:%02d %5d|", tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec, getpid());

           va_start(args,fmt);

           return vprintf(fmt,args);

    }

    输出结果与设想中的顺序不同。因为占用内存的进程不会因为wait pid中的PID参数而固定不变,而是三个子进程会按照第一次运行的顺序继续运行,也就是第一次运行的顺序固定之后,后面的运行顺序不再改变。因此输出顺序结果如下图:

     作者:Nathaneko

  • 相关阅读:
    开发自定义控件步骤
    asp.net后台调用前台js代码
    使用ResolveUrl设置相对路径
    JavaScript获取后台C#变量以及调用后台方法
    使用jquery的验证插件进行客户端验证
    参数化的模糊查询
    使用Microsoft Enterprise Library 5.0记录日志信息
    我的Ajax学习笔记
    我的工作問題集(VS2005)
    存储过程从入门到精通(转载)
  • 原文地址:https://www.cnblogs.com/nathaneko/p/6638672.html
Copyright © 2011-2022 走看看