Linux 编程之进程fork()详解及实例

时间:2019-06-15 03:33来源:计算机教程
查看当前系统进程的状态 ps auxf  对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,它执行一次却返回两个值,完全“不可思议”。先看下面的程序 进程的状态: 

查看当前系统进程的状态 ps auxf 

对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,它执行一次却返回两个值,完全“不可思议”。先看下面的程序

  1. 进程的状态:       

4.小节

Linux fork()详解:

   variable = 9;

    按时间片轮转  
    先来先服务 
    短时间优先 
    按优先级别   

共享内存通常由一个进程创建,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式

在开始之前,我们先来了解一些基本的概念:

  /*下面重新设置信号量*/

D    Uninterruptible sleep (usually IO) 
R    Running or runnable (on run queue) 
S    Interruptible sleep (waiting for an event to complete) 
T    Stopped, either by a job control signal or because it is being traced. 
W    paging (not valid since the 2.6.xx kernel) 
X    dead (should never be seen) 
Z    Defunct ("zombie") process, terminated but not reaped by its parent. 
<    high-priority (not nice to other users) 
N    low-priority (nice to other users) 
L    has pages locked into memory (for real-time and custom IO) 
s    is a session leader 
l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) 
    is in the foreground process group   

 Linux 2.4中增加以支持POSIX线程标准,子进程与父进程共享相同的线程群

  1. 父进程/子进程 , 让一个程序运行起来的进程就叫父进程, 被调用的进程叫子进程   

  2. getpid //获取当前进程的进程号 
       getppid //获取当前进程的父进程号   

  3. fork //创建一个子进程,创建出来的子进程是父进程的一个副本, 除了进程号,父进程号不同。  

Linux进程主要有如下几种状态:用户状态(进程在用户状态下运行的状态)、内核状态(进程在内核状态下运行的状态)、内存中就绪(进程没有执行,但处于就绪状态,只要内核调度它,就可以执行)、内存中睡眠(进程正在睡眠并且处于内存中,没有被交换到SWAP设备)、就绪且换出(进程处于就绪状态,但是必须把它换入内存,内核才能再次调度它进行运行)、睡眠且换出(进程正在睡眠,且被换出内存)、被抢先(进程从内核状态返回用户状态时,内核抢先于它,做了上下文切换,调度了另一个进程,原先这个进程就处于被抢先状态)、创建状态(进程刚被创建,该进程存在,但既不是就绪状态,也不是睡眠状态,这个状态是除了进程0以外的所有进程的最初状态)、僵死状态(进程调用exit结束,进程不再存在,但在进程表项中仍有记录,该记录可由父进程收集)。

您可能感兴趣的文章:

clone

  1. 程序, 没有在运行的可执行文件  

{

    子进程从fork()后开始运行, 它得到的fork返回值为0 
    父进程得到的返回值为子进程的进程号 
    返回值为-1时, 创建失败

  struct sembuf lock_it;

status: 

vnsc5858威尼斯城官网,void *shmat(int shmid, void *addr, int flag); /* 将共享内存连接到自身地址空间中*/

来看一个程序:

  i = semctl(id, 0, GETVAL, 0);

   进程,  运行中的程序   

享),父进程随即就感觉到了,这就是clone的特点。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

 

        就绪   ->>   运行  ->> 等待 
        运行 ->> 就绪 //时间片完了 
        等待 ->> 就绪 //等待的条件完成了   

该函数调用使得进程挂起一个指定的时间,如果指定挂起的时间到了,该调用返回0;如果该函数调用被信号所打断,则返回剩余挂起的时间数

  1. 进程调度的方法:  

  int i;

#include <stdio.h> 
#include <unistd.h> 

int main(void) 
{ 
  pid_t pid ;  
  //printf("hello world n"); 

  //从fork开始就已经产生子进程 
  pid = fork();  //就已经产生新的4G空间,复制空间 
  //创建出来的子进程是父进程的一个副本,除了进程号,父进程号和子进程号不同 
  //printf("hello kittyn"); 
  if(pid == 0)   
  { 
    //子进程运行区 

    printf("child curpid:%d parentpid:%d n" , getpid() , getppid()); 
    return 0 ;  
  } 

  //父进程运行区 
  printf("parent curpid:%d parentpid:%d n" , getpid() , getppid()); 

  return 0 ;  
} 

  printf("value of semaphore at index 0 is %d"n", i);

  for (i = 0; i < 2; i )

  id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);

   }

 

下面是一个使用信号量的例子,该程序创建一个特定的IPC结构的关键字和一个信号量,建立此信号量的索引,修改索引指向的信号量的值,最

exec

}

  int count = 1;

   child_stack = (void **) malloc(16384);

 

The variable is now 42

 

}

/* 进程一:读有名管道*/

Linux的进程间通信(IPC,InterProcess Communication)通信方法有管道、消息队列、共享内存、信号量、套接口等。

。当前进程为父进程,通过fork()会产生一个子进程。对于父进程,fork函数返回子程序的进程号而对于子程序,fork函数则返回零,这就是一个函数返回两次的本质。可以说,fork函数是Unix系统最杰出的成就之一,它是七十年代Unix早期的开发者经过理论和实践上的长期艰苦探

This is parent process

{

(1)测试控制该资源的信号量;

  if (semop(id, &lock_it, 1) ==  - 1)

 

  printf("value of semaphore at index 0 is %d"n", i);

    printf("can not lock semaphore."n");

   void **child_stack;

This is parent process

int main()

  int returned_count;

  else

fork

   printf("We could read from the file"n");

   clone(do_something, child_stack, CLONE_VM|CLONE_FILES, NULL);

  }

   char tempch;

    }

      perror(command);

    else

#include <sys/sem.h>

{

此函数返回创建进程的PID,函数中的flags标志用于设置创建子进程时的相关选项,具体含义如下表:

    printf(">");

      /* 子进程执行此命令*/

且要使用此函数必须在编译内核时设置clone_actually_works_ok选项。

  else

 子进程与父进程运行于相同的内存空间

  }

 

 

运行输出:

此时此刻,我们还没有完全理解fork()函数,再来看下面的一段程序,看看究竟会产生多少个进程,程序的输出是什么?

  int i;

执行结果为:

void main()

int main()

    exit(1);

 

exec函数族的特点体现在:某进程一旦调用了exec类函数,正在执行的程序就被干掉了,系统把代码段替换成新的程序(由exec类函数执行)的代码,并且原有的数据段和堆栈段也被废弃,新的数据段与堆栈段被分配,但是进程号却被保留。也就是说,exec执行的结果为:系统认为正在执行的还是原先的进程,但是进程对应的程序被替换了。

      wait(&rtn);

际地址。此后,进程可以对此地址进行读写操作访问共享内存。

  char buf[BUFFER_LEN];

      execlp(command, command);

};

int main()

CLONE_THREAD

  }

  if (fork() == 0)

(5)进程执行exit调用,进入僵死状态,最终结束。

void main()

    }

  while ((count = fread(buf, 1, BUFFER_LEN, in_file)) > 0)

 在新的namespace启动子进程,namespace描述了进程的文件hierarchy

  }

      /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/

CLONE_FS

后清除信号量:

{

    close(file_descriptors[INPUT]);

进程控制中主要涉及到进程的创建、睡眠和退出等,在Linux中主要提供了fork、exec、clone的进程创建方法,sleep的进程睡眠和exit的进程退出调用,另外Linux还提供了父进程等待子进程结束的系统调用wait。

    printf("in the spawning (parent) process..."n");

管道分为有名管道和无名管道,无名管道只能用于亲属进程之间的通信,而有名管道则可用于无亲属关系的进程之间。

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);

/* 进程二:写有名管道*/

 

  {

 子进程与父进程共享相同的文件描述符(file descriptor)表

  /* 创建一个新的信号量集合*/

 

}

mkfifo是一个函数,mknod是一个系统调用,即我们可以在shell下输出上述命令。

  }

 

int shmget(key_t key, int size, int flag); /* 获得一个共享存储标识符*/

}

  union semun options;

    /*执行父进程*/

      printf("This is parent process"n");

 {

标志

    /* 从终端读取要执行的命令*/

本章讲述了Linux进程的概念,并以多个实例讲解了进程控制及进程间通信方法,理解这一章的内容可以说是理解Linux这个操作系统的关键。

{

       Linux进程在内存中包含三部分数据:代码段、堆栈段和数据段。代码段存放了程序的代码。代码段可以为机器中运行同一程序的数个

      printf("This is child process"n");

  int count = 1;

  key_t unique_key; /* 定义一个IPC关键字*/

2.进程控制

  int i;

  /*创建子进程*/

   return 0;

有名管道创建后,我们可以像读写文件一样读写之:

――进程控制与进程通信编程

  while (1)

    if (fork() == 0)

wait

  lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/

    printf("Error in fork"n");

    for (i = 1; i < 3; i )

}

在Linux中可使用exec函数族,包含多个函数(execl、execlp、execle、execv、execve和execvp),被用于启动一个指定路径和文件名的进程。

本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:

exit

(3)若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1);

  if (out_file == NULL)

   printf("The variable is now %d"n", variable);

  /*定义子进程号*/

}

    printf("received from pipe: %s"n", buf);

  {

CLONE_PARENT

char command[MAX_CMD_LEN];

    {

    /*子进程向父进程写数据,关闭管道的读端*/

      perror("File Read Error");

  {

  i = semctl(id, 0, GETVAL, 0);

fork在英文中是“分叉”的意思,这个名字取得很形象。一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就“分叉”了

  {

      /* 父进程,等待子进程结束,并打印子进程的返回值*/

(4)当进程不再使用一个信号量控制的资源时,信号量值加1,如果此时有进程正在睡眠等待此信号量,则唤醒此进程。

  sprintf(buf, "this is test data for the named pipe example"n");

    {

    {

  fwrite(buf, 1, BUFFER_LEN, out_file);

   _exit(0);

   sleep(1);   /* 延时以便子进程完成关闭文件操作、修改变量 */

#include <stdio.h>

  int rtn; /* 子进程的返回数值*/

  char buf[BUFFER_LEN];

    command[strlen(command) - 1] = 0;

编辑:计算机教程 本文来源:Linux 编程之进程fork()详解及实例

关键词: