精华内容
下载资源
问答
  • printf("无空闲进程控制块,进程创建失败\n"); return; } i=pfree;/*取空闲进程控制块队列的第一个*/ pfree=pcbarea[pfree].next;/*pfree后移*/ /*填写该进程控制块内容:*/ pcbarea[i].name=x; pcbarea[i]....
  • 操作系统-进程控制原语

    千次阅读 2020-02-02 15:34:26
    为了实现进程控制,在...1、进程创建原语 从PCB集合中申请一个空白的PCB,将调用者参数(如进程外部标识符,初始CPU状态,进程优先数,初始内存及申请资源清单)添入该PCB,设置记账数据。置新进程为“就绪”态。 2...

    为了实现进程控制,在操作系统内核中,有一组程序专门用于完成对进程的控制,这些原语至少需要包括创建新进程原语,阻塞进程原语,唤醒进程原语,终止进程原语,系统服务对用户开放,即用户可以通过相应的接口来使用它们。

    1、进程创建原语

    从PCB集合中申请一个空白的PCB,将调用者参数(如进程外部标识符,初始CPU状态,进程优先数,初始内存及申请资源清单)添入该PCB,设置记账数据。置新进程为“就绪”态。

    2、终止进程原语

    用于终止完成的进程,回收其所占资源。包括消去其资源描述块,消去进程的PCB。

    3、阻塞原语

    将进程从运行态变为阻塞态。进程被插入等待事件的队列,同时修改PCB中相应的表项,如进程状态和等待队列指针。

    4、唤醒原语

    将进程从阻塞态变为就绪态。进程从阻塞队列移出,插入就绪队列,等待调度,同时修改PCB中相应的表项,如进程状态。

    展开全文
  • 也就是一个父进程会对应创建一个子进程。那么问题来了,我们平常学的函数大多都是只有一个返回值,但fork()特别就特别在调用一次可以产生两个返回值!fork()第一次返回的是子进程的ID(在父进程中返回子进...

    一.用法解析:

    fork()这个函数,可以说是名如其人了,众所周知fork这个单词本意为叉子,老外取学术名字的时候总会有一些象形的想法,于是就有了下图~

    d45258295f9ec4e2e4ccbcf936c2a8ef.png

    fork()函数是计算机程序设计中的分叉函数。也就是一个父进程会对应创建一个子进程。

    那么问题来了,我们平常学的函数大多都是只有一个返回值,但fork()特别就特别在调用一次可以产生两个返回值!

    fork()第一次返回的是子进程的ID(在父进程中返回子进程ID)

    第二次返回的是0(在子进程中返回0)

    总的来说,fork()可能有三种不同的返回值:

    (1) 在父进程中,fork()返回新创建子进程的进程ID;

    (2)在子进程中,fork()返回0;

    (3)如果出现错误,fork()返回一个负值;

    引用一位网友的话来解释pid的值为什么在父子进程中不同。

    “其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其pid为0.”

    那么fork()是如何返回两次的呢?

    第一步:create(创建子进程)

    第二步:clone(相当于父进程对子进程进行初始化,把自己的0-3G用户空间完全的复制给子进程,下面会详细说)

    return child_pid;(把自己的信息传递给子进程后,返回子进程ID)

    接下来我们可以理解成在fork()函数完成一半时,父进程中断,切换到子进程,子进程接着走完剩下的一半fork()函数,即完成return 0,

    这也就解释了为什么fork()函数返回子进程ID说明当前进程是父进程,返回0说明当前进程是子进程。

    问题又来了,是否在子进程在创建时就进行clone操作呢?

    当然不是,当我们发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程。这种行为是非常耗时的,于是现在的linux提出了

    父进程和子进程共享页面而不是复制页面,只有在子进程有写操作的时候,才进行clone操作,即读时共享,写时复制原则。具体的可以看这篇文章,大佬说的非常详细http://www.cnblogs.com/wuchanming/p/4495479.html

    那么在进行父子进程的拷贝的时候,都拷贝哪些东西呢?

    f718584d62c67ba81a3b6518ca868464.png

    fork出错可能有两种原因:

    1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。

    2)系统内存不足,这时errno的值被设置为ENOMEM。

    创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

    每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。

    二.练手小题

    1.fork()的连续调用:

    下面的程序创建出多少进程?

    fork();

    fork();

    fork();

    fork();

    40b8bc97724bfbd8e54aff0b9d555b39.png

    答案如上图,一共有16个进程,除去主函数的进程,产生了15个进程。

    有人想通过调用printf("+");来统计创建了几个进程,这是不妥当的。具体原因如下代码:

    1 #include

    2 #include

    3 intmain() {4 pid_t fpid;//fpid表示fork函数返回的值5 //printf("fork!");

    6 printf("fork!/n");7 fpid =fork();8 if (fpid < 0)9 printf("error in fork!");10 else if (fpid == 0)11 printf("I am the child process, my process id is %d/n", getpid());12 else

    13 printf("I am the parent process, my process id is %d/n", getpid());14 return 0;15 }

    执行结果如下:

    fork!

    I am the parent process, my process id is 3361

    I am the child process, my process id is 3362

    如果把语句printf("fork!/n");注释掉,执行printf("fork!");

    则新的程序的执行结果是:

    fork!I am the parent process, my process id is 3298

    fork!I am the child process, my process id is 3299

    程序的唯一的区别就在于一个/n回车符号,为什么结果会相差这么大呢?

    这就跟printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上。但是,只要看到有/n 则会立即刷新stdout,因此就马上能够打印了。

    运行了printf("fork!")后,“fork!”仅仅被放到了缓冲里,程序运行到fork时缓冲里面的“fork!”  被子进程复制过去了。因此在子进程度stdout缓冲里面就也有了fork! 。所以,你最终看到的会是fork!  被printf了2次!!!!

    而运行printf("fork! /n")后,“fork!”被立即打印到了屏幕上,之后fork到的子进程里的stdout缓冲里不会有fork! 内容。因此你看到的结果会是fork! 被printf了1次!!!!

    所以说printf("+");不能正确地反应进程的数量。

    2.

    1 fork();2

    3 fork()&&fork()||fork();4

    5 fork();

    答案是总共20个进程,除去main进程,还有19个进程。

    我们再来仔细分析一下,为什么是还有19个进程。

    第一个fork和最后一个fork肯定是会执行的。

    主要在中间3个fork上,可以画一个图进行描述。

    这里就需要注意&&和||运算符。

    A&&B,如果A=0,就没有必要继续执行&&B了;A非0,就需要继续执行&&B。

    A||B,如果A非0,就没有必要继续执行||B了,A=0,就需要继续执行||B。

    fork()对于父进程和子进程的返回值是不同的,按照上面的A&&B和A||B的分支进行画图,可以得出5个分支。

    32c17a1742c5da2b1869a0ef8ec4a4ed.png

    参考资料:

    http://blog.csdn.net/jason314/article/details/5640969

    展开全文
  • 也就是一个父进程会对应创建一个子进程。那么问题来了,我们平常学的函数大多都是只有一个返回值,但fork()特别就特别在调用一次可以产生两个返回值!fork()第一次返回的是子进程的ID(在父进程中返回子进...

    一.用法解析:

    fork()这个函数,可以说是名如其人了,众所周知fork这个单词本意为叉子,老外取学术名字的时候总会有一些象形的想法,于是就有了下图~

    20180111010340308150.png

    fork()函数是计算机程序设计中的分叉函数。也就是一个父进程会对应创建一个子进程。

    那么问题来了,我们平常学的函数大多都是只有一个返回值,但fork()特别就特别在调用一次可以产生两个返回值!

    fork()第一次返回的是子进程的ID(在父进程中返回子进程ID)

    第二次返回的是0(在子进程中返回0)

    总的来说,fork()可能有三种不同的返回值:

    (1) 在父进程中,fork()返回新创建子进程的进程ID;

    (2)在子进程中,fork()返回0;

    (3)如果出现错误,fork()返回一个负值;

    引用一位网友的话来解释pid的值为什么在父子进程中不同。

    “其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其pid为0.”

    那么fork()是如何返回两次的呢?

    第一步:create(创建子进程)

    第二步:clone(相当于父进程对子进程进行初始化,把自己的0-3G用户空间完全的复制给子进程,下面会详细说)

    return child_pid;(把自己的信息传递给子进程后,返回子进程ID)

    接下来我们可以理解成在fork()函数完成一半时,父进程中断,切换到子进程,子进程接着走完剩下的一半fork()函数,即完成return 0,

    这也就解释了为什么fork()函数返回子进程ID说明当前进程是父进程,返回0说明当前进程是子进程。

    问题又来了,是否在子进程在创建时就进行clone操作呢?

    当然不是,当我们发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程。这种行为是非常耗时的,于是现在的linux提出了

    父进程和子进程共享页面而不是复制页面,只有在子进程有写操作的时候,才进行clone操作,即读时共享,写时复制原则。具体的可以看这篇文章,大佬说的非常详细http://www.cnblogs.com/wuchanming/p/4495479.html

    那么在进行父子进程的拷贝的时候,都拷贝哪些东西呢?

    26bf1363d2c1a7fc675d5febc68ebd5c.png

    fork出错可能有两种原因:

    1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。

    2)系统内存不足,这时errno的值被设置为ENOMEM。

    创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

    每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。

    二.练手小题

    1.fork()的连续调用:

    下面的程序创建出多少进程?

    fork();

    fork();

    fork();

    fork();

    有人想通过调用printf("+");来统计创建了几个进程,这是不妥当的。具体原因如下代码:

    1 #include

    2 #include

    3 intmain() {4 pid_t fpid;//fpid表示fork函数返回的值5 //printf("fork!");

    6 printf("fork!/n");7 fpid =fork();8 if (fpid < 0)9 printf("error in fork!");10 else if (fpid == 0)11 printf("I am the child process, my process id is %d/n", getpid());12 else

    13 printf("I am the parent process, my process id is %d/n", getpid());14 return 0;15 }

    执行结果如下:

    fork!

    I am the parent process, my process id is 3361

    I am the child process, my process id is 3362

    如果把语句printf("fork!/n");注释掉,执行printf("fork!");

    则新的程序的执行结果是:

    fork!I am the parent process, my process id is 3298

    fork!I am the child process, my process id is 3299

    程序的唯一的区别就在于一个/n回车符号,为什么结果会相差这么大呢?

    这就跟printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上。但是,只要看到有/n 则会立即刷新stdout,因此就马上能够打印了。

    运行了printf("fork!")后,“fork!”仅仅被放到了缓冲里,程序运行到fork时缓冲里面的“fork!”  被子进程复制过去了。因此在子进程度stdout缓冲里面就也有了fork! 。所以,你最终看到的会是fork!  被printf了2次!!!!

    而运行printf("fork! /n")后,“fork!”被立即打印到了屏幕上,之后fork到的子进程里的stdout缓冲里不会有fork! 内容。因此你看到的结果会是fork! 被printf了1次!!!!

    所以说printf("+");不能正确地反应进程的数量。

    2.

    1 fork();2

    3 fork()&&fork()||fork();4

    5 fork();

    答案是总共20个进程,除去main进程,还有19个进程。

    我们再来仔细分析一下,为什么是还有19个进程。

    第一个fork和最后一个fork肯定是会执行的。

    主要在中间3个fork上,可以画一个图进行描述。

    这里就需要注意&&和||运算符。

    A&&B,如果A=0,就没有必要继续执行&&B了;A非0,就需要继续执行&&B。

    A||B,如果A非0,就没有必要继续执行||B了,A=0,就需要继续执行||B。

    fork()对于父进程和子进程的返回值是不同的,按照上面的A&&B和A||B的分支进行画图,可以得出5个分支。

    20180111010340312057.png

    参考资料:

    http://blog.csdn.net/jason314/article/details/5640969

    展开全文
  • 线程id是在进程地址空间内部,用来标识线程身份的id号。 返回值:本线程id 检查出错返回: 线程中。 线程 ID:pthread_t 类型,本质:在 Linux 下为无符号整数(%lu),其他系统中可能是结构体实现 线程 ID 是进程...

    pthread_self

    pthread_t pthread_self(void);	获取线程id。 线程id是在进程地址空间内部,用来标识线程身份的id号。
    
    返回值:本线程id
    
    检查出错返回:  线程中。
    

    线程 ID:pthread_t 类型,本质:在 Linux 下为无符号整数(%lu),其他系统中可能是结构体实现 线程 ID 是进程内部,识别标志。(两个进程间,线程ID 允许相同)

    注意:不应使用全局变量 pthread_t tid,在子线程中通过 pthread_create 传出参数来获取线程 ID,而应使用pthread_self。

    pthread_create

    int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*start_rountn)(void *), void *arg); 创建子线程,类似于进程中的fork函数。
    
    ​	参1:传出参数,表新创建的子线程 id
    
    ​	参2:线程属性。传NULL表使用默认属性。
    
    ​	参3:子线程回调函数。创建成功,ptherad_create函数返回时,该函数会被自动调用。
    ​	
    ​	参4:参3的参数。没有的话,传NULL
    
    ​	返回值:成功:0
    
    ​		失败:errno-----Linux 环境下,所有线程特点,失败均直接返回错误号。
    

    创建一个进程的简单demo

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <pthread.h>
    
    void sys_err(const char *str)
    {
    	perror(str);
    	exit(1);
    }
    
    void *tfn(void *arg)
    {
        printf("thread: pid = %d, tid = %lu\n", getpid(), pthread_self());
    
        return NULL;
    }
    
    int main(int argc, char *argv[])
    {
        pthread_t tid;
    
        int ret = pthread_create(&tid, NULL, tfn, NULL);
        if (ret != 0) {
            perror("pthread_create error");
        }
    
        printf("main: pid = %d, tid = %lu\n", getpid(), pthread_self());
        sleep(1);
    
    	return 0;
    }
    
    

    pthread_exit

    void pthread_exit(void *retval);  退出当前线程。
    
    ​	retval:退出值。 无退出值时,NULL
    
    ​	pthread_exit(): 退出当前线程。
    

    pthread_join

    int pthread_join(pthread_t thread, void **retval);	阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。 
    
    	thread: 待回收的线程id
    
    	retval:传出参数。 回收的那个线程的退出值。
    
    		线程异常借助,值为 -1。
    
    	返回值:成功:0
    
    		   失败:errno
    
    1. 如果thread 线程通过return 返回,retval 所指向的单元里存放的是 thread 线程函数的返回值。
    2. 如果 thread 线程被别的线程调用 pthread_cancel 异常终止掉,retval 所指向的单元里存放的是常数PTHREAD_CANCELED。
    3. 如果thread 线程是自己调用 pthread_exit 终止的,retval 所指向的单元存放的是传给 pthread_exit 的参数。
    4. 如果对thread 线程的终止状态不感兴趣,可以传NULL 给retval 参数。

    pthread_cancel

    int pthread_cancel(pthread_t thread);		杀死一个线程。  需要到达取消点(保存点)
    
    thread: 待杀死的线程id
    ​	返回值:成功:0
    ​		   失败:errno
    

    如果,子线程没有到达取消点, 那么 pthread_cancel 无效。

    ​ 我们可以在程序中,手动添加一个取消点。使用 pthread_testcancel();

    ​ 成功被 pthread_cancel() 杀死的线程,返回 -1.使用pthead_join 回收。

    pthread_detach

    int pthread_detach(pthread_t thread);    实现线程分离
    
    thread: 待分离的线程id
    
    ​	返回值:成功:0
    
    ​		失败:errno
    

    线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。
    进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资源仍存于系统中,导致内核认为该进程仍存在。

    控制原语对比

    线程控制原语 进程控制原语
    pthread_create() fork();
    pthread_self() getpid();
    pthread_exit() exit(); / return
    pthread_join() wait()/waitpid()
    pthread_cancel() kill()
    pthread_detach()
    展开全文
  • linux进程控制原语

    千次阅读 2015-01-29 11:49:43
    一,创建原语:fork函数族 1,fork() 2,vfork 二,执行(加载)原语:exec函数族 1,execl 2,execv 3,execle 4,execve 5,execlp 6,execvp 三,退出/等待退出原语:exit函数族,wait函数族
  • 进程控制原语

    千次阅读 2005-02-03 14:34:00
    UNIX下的进程控制原语用于控制进程创建、执行、终止等。其基本原语如下: 用fork创建进程,用exec执行新的程序,exit函数和两个wait函数处理终止和等待终止。下面分别讲解一下: 除了交换进程(swapper)、...
  • 一、创建原语 1)fork() 2)vfork() 二、执行(加载)原语:exec函数族 1)execl 2) execv 3) execle 4) execve 5) execlp 6) execvp 三、退出/等待原语:exit()函数族,wait函数族 ...
  • 模拟进程创建、终止、阻塞、唤醒原语操作系统原理
  • Linux进程原语及功能:fork:创建一个新的子进程;exec族(execl、execlp、execle、execv、execvp、execve):执行一个文件;用fork创建进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要...
  • 进程创建、终止、阻塞、调度、唤醒原语有助于对操作系统中近程功能的了解,掌握操作系统模块的设计方法和工作原理
  • 4.1 进程概念 4.1.1 进程基本概念:描述和管理程序“运行过程”--进程 A、定义:进程是程序在某个数据集合上的一次运行活动。数据集合:软/硬件环境,多个进程共存/共享的环境 B、进程的特征: 1. 动态性:进程是...
  • 1. 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是...在父进程中,返回创建的子进程的pid;在子进程中返回0;出错,返回-1。 1.子进程复制了父进程的PC...
  • 进程和线程我们先从 Linux 的进程谈起,操作系统要运行一个可执行程序,首先要将程序文件加载到内存,然后 CPU 去读取和执行程序指令,而一个进程就是“一次程序的运行过程”,内核会给每一个进程创建一个名为task_...
  • 进程原语和线程原语的比较

    千次阅读 2012-12-03 19:39:52
    进程原语  线程原语  描述  fork  pthread_create  创建新的控制流  exit  pthread_exit  从现有的控制流中退出  waitpid  pthread_join  从控制流中
  • (二十二)进程——进程原语fork

    千次阅读 2017-01-06 17:43:59
    而一个进程包括代码、数据和分配给进程的资源,所以fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,一个进程调用fork()函数后,系统先给新的进程分配资源,包括存储数据和代码的空间。...
  • 什么是进程进程的定义是:...查看进程在Windows系统中,打开QQ程序这个软件,系统就会创建一个进程,通过任务栏管理器可以方便直观的查看。如下图所示:在Linux操作系统中,执行ps -aux指令,下图所示。进程特征动态...
  • 创建原语 撤销原语 挂起原语 激活原语 阻塞原语 唤醒原语 进程调度原语 1.何时调用阻塞原语? 当正在运行的进程需要等待某一事 件而发生运行受阻时,它通过中断请求系统服务。 系统按照进程的需求进行适当处理后,...
  • 2.1.3 操作系统之原语实现对进程的控制

    千次阅读 多人点赞 2020-03-15 16:56:00
    进程控制的五种原语(1)进程创建原语(2)进程的终止原语(3)进程的唤醒和阻塞原语(4)进程的切换原语 0.思维导图 1.什么是进程控制? 2.原语实现对进程的控制 关于原语的作用和处在操作系统内核的重要地位...
  • 进程与线程原语

    2014-07-08 00:45:30
    fork pthread_create 创建新的控制流 exit p
  • 二、与进程创建、执行有关的系统调用说明 fork()系统调用: exec 系统调用: wait() 和 waitpid() 系统调用: getpid()系统调用语法: 三、与进程控制有关的系统调用说明 kill 系统调用: pause 系统调用: ...
  • 1、 创建原语:创建一个就绪状态的进程,使进程从创建状态变迁为就绪状态。 2、 撤销原语:使进程从执行状态变迁为完成状态。 3、 阻塞原语:使进程从运行状态变迁为阻塞状态。 4、 唤醒原语:使进程从阻塞状态...
  • 前言先来看看一则小故事我们写好的一行行代码,为了让其工作起来,我们还得把它送进城(进程)里,那既然进了城里,那肯定不能胡作非为了。城里人有城里人的规矩,城中有个专门管辖你们的城管(操作系统),人家让你休息...
  • 进程控制原语有: 创建原语 撤销原语 阻塞原语 唤醒原语 A:创建 B:撤销 C:阻塞 D:唤醒 (七) 线程 (1) 为什么引入线程的概念 实施进程的创建、删除和切换过程中时空代价大,限制了系统中的进程数目和并发活动的...
  • 操作系统学习架构图目录1 进程的概念及特征1.1 进程的引入1.2 进程的概念1.3 进程的理解2 进程的状态及转换2.1 三态模型2.2 五态模型3 进程组织、控制与通信3.1 进程的组织3.2 进程控制块3.3 进程的控制3.4 进程通信...
  • 进程原语一. fork函数 1. 函数原型 pid_t fork(void); 子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。 2. 以具体的程序讲解fork函数特点 第一段代码 #include <stdio.h> #include <...
  • linux进程原语之fork()

    2017-12-07 23:47:00
    一....也就是一个父进程会对应创建一个子进程。 那么问题来了,我们平常学的函数大多都是只有一个返回值,但fork()特别就特别在调用一次可以产生两个返回值! fork()第一次返回的是子进程的ID...
  • Linux进程控制fork原语

    千次阅读 2011-12-16 17:09:07
    1)fork()系统调用是创建一个新进程的首选方式,fork的返回值要么是0,要么是非0,父进程与子进程的根本区别在于fork函数的返回值. 2)vfork()系统调用除了能保证用户空间内存不会被复制之外,它与fork几乎是完全相同的...
  • [[NOTE]进程进程管理

    2019-10-17 20:51:31
    文章目录进程顺序程序和并发顺序程序并发程序性质:无封闭性和可再现性进程进程的基本状态进程的转换进程描述(*)进程控制块PCB进程管理进程状态的变化进程控制原语进程创建原语进程撤销原语进程等待原语进程唤醒原语...
  • 在操作系统中,一般把进程控制用的程序段称为原语原语的特点是执行期间不允许中断,它是一个不可分割的基本单位。 进程创建 程序从硬盘中加载到内存中,操作系统为新进程分配一个唯一的进程标识号,并申请一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 414
精华内容 165
关键字:

进程创建原语