c语言初始化字符串 函数 manment,[转载]3.09进程(C语言班最后一天的课程)

1,进程:是容器,是内存上的概念。线程是CPU的概念。

2,fork的作用是根据一个现有的进程复制出一个新进程,原来的进程称为父进程(Parents Process),新进程称为子进程(Child Process)。

系统中同时运行着许多进程,这些进程都是从最初只有一个进程开始一个一个复制出来的。

分进程函数fork(),用来开辟子进程。执行fork()之后,会有两个进程,一个是原来的那个,一个是新生成的子进程。这两个进程都会执行程序下面的代码。pid = fork();pid得到的是返回子进程的id,不是自己的id。

1.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(pid > 0){

printf("Parents!n");

}

if(0 == pid){

printf("Child!n");

}

printf("Hello world!n");

return 0;

}

3,先让父进程睡1秒,会先执行子进程。

2.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

printf("Child!n");

}else{

sleep(1);

printf("Parents!n");

}

return 0;

}

如果父进程结束后,sleep(1);子进程会打印到终端。

3.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

sleep(1);

printf("Son!n");

}else{

printf("Father!n");

}

return 0;

}

4,进程号:pid 。getppid()是得到当前进程父进程的pid;getpid()是得到当前进程的pid。

如果子进程getppid()时,父进程已经死掉,子进程就会被托管,那getppid()的值就为1。

所以父进程要sleep(1),这样子进程getppid()时,得到的就是此进程父进程的pid。

父进程getppid()时,得到的是终端的pid。

4.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

printf("Child!ngetppid=%d getpid=%d pid=%dn", getppid(),

getpid(), pid);

}else{

printf("Parents!ngetppid=%d getpid=%d pid=%dn", getppid(),

getpid(), pid);

sleep(1);

}

return 0;

}

5,ps查看进程;

ps -jas 查看所有的进程。

6,探讨怎么让父进程知道子进程结束?

exit(0)不会结束整个程序,只会结束一个进程。wait(NULL)等待自己子进程的结束。

父进程执行到wait()时,会进入休眠,子进程结束时,会发一个信号,wait()会捕捉到这个信号,以此来唤醒父进程。

5.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

sleep(3);

printf("Child!n");

exit(0);

}

wait(NULL);

printf("Parents!n");

return 0;

}

7,探讨父进程与子进程关于变量使用的问题?

在fork()之后,会把原来的内存完全复制一份,但不管怎么样更改,都只会各改各的,互不干扰。

6.c

#include

#include

#include

#include

int main(void)

{

int a = 5;

int * p = &a;

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(pid > 0){

*p = 6;

printf("Parents:%dn", *p);

}else{

printf("Child:%dn", *p);

}

return 0;

}

8,怎么样杀死进程?

下面的程序是个死循环,只能重新开一个终端,执行“kill -9 进程号”。

如果执行以下命令,一定要删除交换文件:

$vi 5.c //进入5.c 此进程进程号为3456

$Ctrl + z

//暂停当前程序运行

$kill -9 3456 //杀死vi 5.c,这个进程

$fg

//回到刚暂停的程序中,会报错,因为那个进程已经被杀死了。要删除那个交换文件才能执行这个操作。

$ls -a//查看所有文件,能把交换文件查看出来。

$rm -fr ..5.c.swap. //删除交换文件。

$fg

7.c

#include

#include

#include

#include

int main(void)

{

pid_t pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

while(1){

printf("Child!n");

}

}else{

printf("Parents!n");

}

return 0;

}

9,exec族:用来代替原来进程,执行的时候完全代替,不会再回来。

#include

所需头文件

(1)execl("/bin/ls", "ls", "-l",

NULL); 后面一定要加NULL,表示参数传完了。

int

execl(const char *path, const char *arg0, ... )

8.c

#include

#include

#include

#include

int main(void)

{

int ret = execl("/bin/ls", "ls", "-l", NULL);

if(ret < 0){

perror("execl!n");

exit(0);

}

printf("Hello world!n");

return 0;

}

(2)

execlp已经安装过的程序,不需要写路径。

int

execlp(const char *file, const char *arg0, ... );

9.c

#include

#include

#include

#include

int main(void)

{

int ret = execlp("ls", "ls", "-l", NULL);

if(ret < 0){

perror("execl!n");

exit(0);

}

printf("Hello world!n");

return 0;

}

(3)int execv(const char *path, char

*const argv[]);

int

execvp(const char *file, char *const argv[]);

10.c

#include

#include

#include

#include

int main(void)

{

char * buf[5] = {};

buf[0] = "ls";

buf[1] = "-l";

buf[2] = NULL;

int ret = execv("/bin/ls", buf);

// int ret =

execvp("ls", buf);

if(ret < 0){

perror("execv");

exit(0);

}

return 0;

}

10,whereis ls 查看ls的路径。

11,-rwx-rwx-rwx:普通文件

drwx-rwx-rwx:d代表是一个文件夹

lrwx-rwx-rwx:l代表是一个快捷方式

12,cd是shell的内置命令。如果输入等于cd,则用chdir(),它并没有fork()子进程,是父进程在执行chdir()。

11.c

#include

#include

#include

int main(void)

{

chdir("dic");

//这个目录要事先创建好。

mkdir("./ttt");

return 0;

}

如果用execlp(),会达不到想要的结果。

12.c

#include

#include

#include

#include

int main(void)

{

int ret = execlp("cd", "cd", "/", NULL);

if(ret < 0){

perror("execlp");

exit(0);

}

return 0;

}

13,一定要记住(固定格式):切割字符串函数strtok()

13.c

#include

#include

#include

#include

#define BUF 512

#define BUFF 10

int main(void)

{

char buf[BUF] = {};

ssize_t ret = read(0, buf, BUF);

int i = 0;

char * buff[BUFF] = {};

char * p = buf;

while(1){

p = strtok(p, " n");

if(!p)

break;

buff[i++] = p;

p = NULL;

}

for(i = 0; i < BUFF; i++){

if(NULL == buff[i])

break;

printf("%sn", buff[i]);

}

execvp(buff[0], buff);

return 0;

}

14,编写一个自己的终端

14.c

#include

#include

#include

#include

#define BUF 512

#define BUFF 10

int main(void)

{

char buf[BUF];

char * buff[BUFF];

char * p = buf;

int i = 0;

pid_t pid;

int ret = 0;

while(1){

write(1, "myshell$", 8);

memset(buf, 0,

BUF);

read(0, buf, BUF);

while(1){

p = strtok(p, "n ");

if(!p){

break;

}

buff[i++] = p;

p = NULL;

}

buff[i] = NULL;

if(strcmp(buff[0], "cd") == 0){

chdir(buff[1]);

continue;

}

pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}else if(pid == 0){

ret = execvp(buff[0], buff);

if(ret < 0){

perror("execvp");

exit(0);

}

}else{

wait(NULL);

}

}

return 0;

}

15,仔细探讨fork()的用法。

15.c

#include

#include

#include

#include

int main(void)

{

pid_t pid;

char * message;

int n = 0;

pid = fork();

if(pid < 0){

perror("fork");

exit(0);

}

if(0 == pid){

message = "This is the childn";

n = 6;

}else{

message = "This is the parentn";

n = 3;

}

for(;n > 0; n--){

printf("%s", message);

sleep(1);

}

return 0;

}

程序运行顺序如下:

(1)父进程初始化。

(2)父进程调用fork,这是一个系统调用,因此进入内核。

(3)内核根据父进程复制出一个子进程,父进程和子进程的PCB信息相同,用户态代码和数据也相同。因此,子进程现在的状态和父进程一样,做完了初始化,刚调用了fork进入内核,还没有从内核返回。

(4)现在有两个一模一样的进程看起来都调用了fork进入内核等待从内核返回(实际上fork只调用了一次),系统中还有很多别的进程也等待从内核返回。是父进程先返回还是子进程先返回,还是这两个进程都等待,先去调度执行别的进程,这都不一定,取决于内核的调度算法。

(5)如果某个时刻父进程被调度执行了,从内核返回后就从fork函数返回,保存在变量pid中的返回值是子进程的id,是一个大于0的整数,因此执行下面else分支,然后执行for循环,打印"This is parentn"三次之后终止。

(6)如果某个时刻子进程被调度执行了,从内核返回后就从fork函数返回,保存在变量pid中的返回值是0,因此执行下面的if(0 == pid)分支,然后执行for循环,打印"This is childn"六次这样之后终止。fork调用把父进程的数据复制一份给子进程,但此后二者互不影响,在这个例子中,fork调用之后父进程和子进程的变量message和n被赋予不同的值,互不影响。

(7)父进程每打印一条信息就睡眠1秒,这时内核调度别的进程执行,在这1秒这么长的间隙里(对于计算机来说1秒很长了)子进程很有可能被调度到。同样地,子进程每打印一条信息就睡眠1秒,在这1秒期间父进程也很有可能被调度到。所以程序运行地结果基本上是父子进程交替打印,但这也不一定的,取决于系统中其他进程的运行情况和内核的调动算法,如果系统中其他进程非常繁忙则有可能观察到不同的结果。

(8)这个程序是在Shell下运行的,因此Shell进程是父进程的父进程。父进程运行时Shell进程处于等待状态,当父进程终止时Shell进程认为命令执行结束了,于是打印Shell提示符,而事实上子进程这时还没结束,所以子进程的消息打印到了Shell提示符后面。最后光标停在This is the child的下一行,这时用户仍然可以敲命令,即使命令不是紧跟在提示符后面,Shell也能正确读取。

fork函数:

(1)fork函数的特点"调用一次,返回两次",在父进程中调用一次,在父进程和子进程中各返回一次。一开始是一个控制流程,调用fork之后发生了分叉,变成两个控制流程,这也就是"fork"(分叉)这个名字的由来了。子进程中fork的返回值是0,而父进程中fork的返回值则是子进程的id(从根本上说fork是从内核返回的,内核自有办法让父进程和子进程返回不同的值),这样当fork函数返回后,程序员可以根据返回值的不同让父进程和子进程执行不同的代码。

(2)fork的返回值这样规定也是有道理的。fork在子进程中返回0,子进程仍可以调用getpid函数得到自己的进程id,也可以调用getppid函数得到父进程的id。在父进程中用getpid可以得到自己的进程id,然而要想得到子进程的id,只有将fork的返回值记录下来,别无他法。

(3)fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说file结构体的引用计数要增加。

16,exec函数

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

exec族

man

3 exec

头文件:#include

int execl(const char *path, const char *arg0, ... );

int execlp(const char *file, const char *arg0, ... );

int execle(const char *path, const char *arg0, ...);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execvP(const char *file, const char *search_path, char *const

argv[]);

man 2 execve

int execve(const char *path, char *const argv[], char *const

envp[]);

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。

不带p(表示path)的exec函数第一个参数必须是程序的相对路径或绝对路径,例如"/bin/ls"或"./a.out",而不能是"ls"或"a.out"。对于带字母p的函数:如果参数中包含/,则将其视为路径名。否则视为不带路径的程序名,在PATH环境变量的目录列表中搜索这个程序。

带由字母l(表示list)的exec函数要求将新程序的每个命令行参数都作为一个参数传给它,命令行参数的个数是可变的,因此函数原型中有…,…中的最有一个可变参数应该是NULL,起sentinel的作用。

对于带有字母v(表示vector)的函数,则应该先构造一个指向各参数的指针数组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数的argv参数或者环境变量一样。

对于以e(envirnoment)结尾的exec函数,可以把一份新的环境变量传给它,其他exec函数仍使用当前的环境变量表执行新程序。

事实上,只有execve是真正的系统调用,其他五个函数最终都调用execve,所以execve在man手册第2节,其他函数在man手册第3节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

减小程序规模!稀疏数组Sparsearray,数据结构二维数组与稀疏数组转换,Java实现

文章目录基本介绍应用实例基本介绍 当一个数组中大部分元素为0&#xff0c;或者为同一个值的数组时&#xff0c;可以使用稀疏数组来保存该数组。 稀疏数组的处理方法是: ①记录数组一共有几行几列&#xff0c;有多少个不同的值&#xff08;0除外&#xff09;。 ②把具有不同值…

ug弹簧可变性装配_弹簧可配置魔术

ug弹簧可变性装配Spring框架具有几个提供一系列服务的模块&#xff0c;其中许多模块仅可用于托管对象&#xff08;Spring Bean&#xff09;。有关这些服务的一些示例是依赖注入&#xff0c;事务管理&#xff0c;AOP服务等。当我们使用时&#xff0c;一切都很好对象即服务&#…

C语言课程设计报告输出杨辉三角,C语言学习:在屏幕上输出杨辉三角

杨辉三角的规律是&#xff1a;它的两条斜边都是由数字1组成的&#xff0c;而其余的数则是等于它肩上的两个数之和。 代码如下&#xff1a;#include#includeint main(){int i,j,k,arr[10][10]{0};/*arr[11][11]必须初始化&#xff0c;初始化为{0}*/printf("打印出杨辉三角&…

朴实!简单!依你所好,MySQL排序查询ORDER BY

1、基本语法 SELECT查询列表 FROM表 #可选&#xff08;WHERE ...&#xff09; ORDER BY排序列表 DESC/ASC;升序是ASC或者不写&#xff0c;降序是DESC 2、案例一&#xff1a;按字段&#xff08;*代表全部&#xff09; SELECT* FROMemployees ORDER BYsalary DESC;3、案例二&am…

使用一个命令执行单个Java源文件

JDK增强提案 &#xff08; JEP &#xff09; 草案于2017年末创建&#xff0c;名为“ 启动单文件源代码程序 ”&#xff08;其相关的JDK问题为JDK-8192920 &#xff09;。 顾名思义&#xff0c;该JEP草案旨在“增强Java启动器以支持运行作为Java源代码的单个文件提供的程序。” …

习惯性朴实简单!一起学习MySQL常见单行函数,字符数学日期流程控制

文章目录一、字符函数二、数学函数三、日期函数四、其他函数五、流程控制函数一、字符函数 1、大小写控制函数 ①UPPER()&#xff1a;转换成大写 SELECT UPPER(Hello);②LOWER()&#xff1a;转换成小写 SELECT LOWER(Hello);2、字符控制函数 ①LENGTH()&#xff1a;获取参数…

c语言程序设计陈雪芳,东莞理工学院C语言课程设计.doc

東莞理工學院C语言程序设计课程设计报告书院系名称 机械工程学院专业班级 2013级机械设计制造及其自动化1班组长成员指导教师 陈雪芳完成时间 2014年6月1日目 录1、系统功能及任务描述………………………..1.1系统总体功能描述………………………….1.2主要任务描述…………………

不可上位!数据结构队列,老实排队,Java实现数组模拟队列及可复用环形队列

文章目录队列简介数组模拟队列&#xff08;无法复用&#xff09;数组模拟环形队列&#xff08;可复用&#xff09;队列简介 队列是一个有序列表&#xff0c;可以用数组或是链表来实现。 遵循先入先出的原则。即先存入队列的数据&#xff0c;先取出&#xff0c;后存入的后取出…

c语言循环与数组训练题,C语言循环数组练习题解读.doc

循环数组练习题一&#xff0e;选择题1&#xff0e;for(i0;i<10;i); 结束后&#xff0c; i 的值是&#xff1b; BA9B10C11D122&#xff0e;下面程序的循环次数是&#xff1a;Dint k0;while(k<10){if(k<1)continue;if(k5)break;k;}A.5B6C4D 死循环&#xff0c;不能确定循…

Java更快地对基元数组进行排序?

看起来Java的原语排序数组在不久的将来可能会提高性能。 弗拉基米尔雅罗斯拉夫斯基&#xff08;Vladimir Yaroslavskiy&#xff09;已在core-libs-dev邮件列表中发布了一条消息 &#xff0c;标题为“ Dual-Pivot Quicksort的新优化版本 ”&#xff0c;其中Yaroslavskiy撰写了“…

多对一!分组查询!MySQL分组函数,聚合函数,分组查询

文章目录一、简单使用二、搭配DISTINCT去重三、COUNT()详细介绍四、分组查询一、简单使用 SUM&#xff1a;求和&#xff08;一般用于处理数值型&#xff09; AVG&#xff1a;平均&#xff08;一般用于处理数值型&#xff09; MAX&#xff1a;最大&#xff08;也可以用于处理字…

华工网络教育C语言校考答案,计算机应用基础(统考)随堂练习2017秋华工答案.docx...

计算机应用基础(统考)随堂练习第一章计算机基础知识计算机能直接识别并执行的语言是 ______。A. 汇编语言B.自然语言C.机器语言D.高级语言答题&#xff1a;A. B. C. D.参考答案&#xff1a; C计算机存储容量的基本单位是 _____。A. 赫兹B.字节( Byte)C.位 (bit)D. 波特答题&…

数据结构单链表SingleLinkedList,Java实现单链表增删改查

文章目录链表介绍应用示例链表介绍 链表是有序的列表&#xff0c;但是它在内存中是存储是不连续的&#xff0c;如下&#xff1a; 链表是以节点的方式来存储&#xff0c;是链式存储&#xff1a; ①每个节点包含data域存储数据&#xff0c;next域指向下一个节点 ②链表的各个节点…

c语言队列原理的实现,c印记(十二):队列queue原理与实现

一、简而言之在百度百科里面摘取了一段关于队列(queue)的介绍&#xff1a;队列是一种特殊的线性表&#xff0c;特殊之处在于它只允许在表的前端(front)进行删除操作&#xff0c;而在表的后端(rear)进行插入操作&#xff0c;和栈一样&#xff0c;队列是一种操作受限制的线性表。…

通用版!完整代码,单链表SingleLinkedList增删改查,反转,逆序,有效数据等Java实现

文章目录节点类链表类&#xff08;主要&#xff09;测试类小结节点类 可以根据需要&#xff0c;对节点属性进行修改。注意重写toString()方法&#xff0c;以便后续的输出操作。 //节点类 class Node {public int id;public String name;public Node next;public Node(int id,…

Java 10 – JEP 286:局部变量类型推断

Java 10即将发布&#xff0c;RC Build可在此处获得 。 可在此处找到此发行版的目标功能。 在针对Java 10的所有JEP中&#xff0c;开发人员社区中最有趣且最受关注的是286&#xff1a;Local-Variable Type Inference 。 什么是局部变量类型推断&#xff1f; 我们在Java 8中看到…

w ndows7与XP哪个好,Win7系统与Win XP系统哪个更好?Windows7与WindowsXP区别介绍-系统城·电脑系统下载之家...

虽然微软已经停止对xp系统的维护&#xff0c;但是仍有不少用户有这样一个疑惑&#xff1a;Win7系统与WinXP系统哪个更好&#xff1f;接下来&#xff0c;小编就向大家具体介绍Windows7与WindowsXP的区别&#xff0c;让你知道到底哪个系统会更好一些。首先跟系统城小编一起来看微…

一文完整MySQL连接查询,笛卡尔乘积,内连接外连接交叉连接

文章目录笛卡尔乘积连接查询分类等值连接非等值连接自连接外连接交叉连接连接查询又称为多表查询&#xff0c;当查询的字段来自于多个表时&#xff0c;使用连接查询。 笛卡尔乘积 笛卡尔乘积现象&#xff1a;表1有m行&#xff0c;表2有n行&#xff0c;结果有m*n行 发生原因&a…

android 自定义表单,Android实现Ant Design 自定义表单组件

Ant Design 组件提供了Input&#xff0c;InputNumber&#xff0c;Radio&#xff0c;Select&#xff0c;uplod等表单组件&#xff0c;但实际开发中这是不能满足需求&#xff0c;同时我们希望可以继续使用Form提供的验证和提示等方法(使用起来确实很爽)&#xff0c;这时需要自己动…

逆向行驶!数据结构双向链表DoubleLinkedList,Java实现增删改查

文章目录节点类链表类测试类双向链表也叫双链表&#xff0c;是链表的一种&#xff0c;它的每个数据结点中都有两个指针&#xff0c;分别指向直接后继和直接前驱。所以&#xff0c;从双向链表中的任意一个结点开始&#xff0c;都可以很方便地访问它的前驱结点和后继结点。 节点类…