主题:进程控制编程

参考书本《高质量嵌入式linux C编程》
一、为何需要多线程,为何需要并发
    首先解释什么是线程:通常在硬盘上的一个可执行文件(例如在windows上的是.exe文件,在Linux上是只要有可执行权限x) 称之为程序。当运行一个程序之后,程序就会加载到内存中,在运行的过程中就称之为线程。因为可以发现,一个程序可以创造多个线程。但为何需要多线程呢?为何需要并发呢?作为一枚单片机爱好者,在写裸机程序的时候,只有一个main函数,此时同一时间内只能执行一个程序。就比如说,一个快餐店只有一个服务员,他既要负责做餐,还要负责卖,还要负责收钱,他是不是很累。如果有了鸣人(火影忍者人物)的分身术,他可创造三个分身,一个专门做餐,一个专门收钱,最后一个专门负责卖餐。这就是多线程的应用。
  1.1 进程
对于单cpu的计算机来说,每个时刻只能执行一条指令代码。而linux是多任务系统,那么linux是如何实现多进程同时执行呢?其实在linux中使用了进程调度算法,首先,为每个进程分配一定的运行时间,这个时间往往很短,然后根据算法,从众多进程中挑选出一个进程进行运行,其他进程都处于停滞状态,当运行时间耗尽之后或者进程执行完毕之后,Linux会重新进行算法调度,挑选下一个进程进行运行。其中,每个进程可以运行时间很短,一般都是毫秒级。因此,从使用者来说,感觉就像多个线程同时运行。需要注意的是,Linux系统中会为每个进程很配进程控制块(PCB),PCB中包含了很多重要的信息供系统和进程本身使用,最主要的有进程ID,也称之为进程标识符,是一个非负整数,它与每一个进程一一对应。
  1.2 进程分类
进程一般分为交互进程,批处理进程,和守护进程
  1.3父子进程
父进程和子进程的关系是管理与被管理,当父进程结束,子进程也随之结束。而子进程结束,父进程任然可以存在。子进程如果结束了,而父进程却没有为其收尸,子进程就会变成僵尸进程,其不占用任何内存空间,仅仅会在进程列表中占有一个位置。太多僵尸进程会造成系统奔溃。即使当父进程在结束之前没有为子进程收尸,系统init进程会自动接收子进程为其收尸,但是父进程一直处于死循环没有结束,子进程的产生的僵尸进程就会一直存在。
如何避免僵尸进程:父进程通过wait和waitpid等函数等待子进程结束,但这会导致父进程挂起。如果父进程很忙,那么可以调用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程就会收到信号,可以在hander中调用wait回收。如果父进程不关心子进程什么时候结束,可以使用singal(SIGCHLD,SIG_IGN),忽略,然后子进程结束后,由系统内核回收。

头文件

#include <sys/wait.h>
#include <sys/types.h>

定义

pid_t wait(int *status)

函数说明

父进程获取子进程的状态

返回值

返回子进程ID,错误-1


二、 Linux进程管理
   2.1 各种进程命令
        查看进程列表,静态
        ps -aux或者ps -lax

        查询进程
        pgrep 参数 程序名 
         -l 列出  程序名和进程ID
        -o 进程起始ID
        -n 进程终止ID
       

       终止进程
          kill 【信号代码】 进程ID 
           一般来说信号代码 -9,表示强行终止
         killall 通过程序名直接杀死进程

      动态监视进程
         top

三、进程创建
   3.1 获取进程
    

头文件

#include <unistd.h>
            #include <sys/types.h>

定义

pid_t getpid(void)

函数说明

获取正在执行进程的ID

返回值

返回进程ID

头文件

#include <unistd.h>
            #include <sys/types.h>

定义

pid_t getppid(void)

函数说明

获取父进程的ID

返回值

返回父进程ID

   3.2 创建进程
    

 头文件

#include <unistd.h>

#include <sys/types.h>

 定义

pid_t fork(void)

 函数说明

创建新进程,子进程只是复制父进程的资源,子进程有其自己的task_struct和PID,而且子进程和父进程所停留的代码位置是一样的。父子进程之间不会共享数据空间,堆栈。在子进程中修改变量的数据不会影响父进程。

返回值

在父进程中返回子进程ID,在子进程返回0,错误-1

头文件

             #include <unistd.h>

#include <sys/types.h>

定义

pid_t vfork(void)

函数说明

创建新进程,子进程共享父进程数据空间,堆栈。在子进程中修改变量的数据会影响父进程。

返回值

在父进程中返回子进程ID,在子进程返回0,错误-1

代码测试:

 */***********************************************************************
    > File Name: my_fork.c
    > Author:silence
    > Mail: [email protected] 
    > Created Time: 2018年12月19日 星期三 12时38分45秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<error.h>

//目的:觀察子進場是否共享父進場資源

int main(void)
{
        pid_t pid;
        int tmp = 10;

        pid = fork();
        if(pid < 0)
        {
                printf("create progress failure\n");
                exit(1);
        }
        if(pid == 0)
        {
                //child progress
                printf("-----I am child progress-----\n");
                tmp = 20;
                printf("tmp = %d\n",tmp);
        }
        else
        {
                //father progress
		sleep(1);
                printf("-----I am father progress-----\n");
                tmp = 30;
                printf("tmp = %d\n",tmp);
        }

        return 0;
}

运行结果:
-----I am child progress-----
tmp = 20
-----I am father progress-----
tmp = 10

结论:fork创建的子进程不共享父进程资源

   

/*************************************************************************
    > File Name: my_vfork.c
    > Author:silence
    > Mail: [email protected] 
    > Created Time: 2018年12月19日 星期三 12时50分45秒
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<error.h>

//目的:vfork()創察子進場是否共享父進場資源

int main(void)
{
	pid_t pid;
	int tmp = 10;

	pid = vfork();
	if(pid < 0)
	{
		printf("create progress failure\n");
		exit(1);
	}
	if(pid == 0)
	{
		//child progress
		printf("-----I am child progress-----\n");
		tmp = 20;
		printf("tmp = %d\n",tmp);
                exit(0);
	}
	else
	{
		//father progress
                sleep(1);
		printf("-----I am father progress-----\n");
		printf("tmp = %d\n",tmp);
	}

	return 0;
}

运行结果:
-----I am child progress-----
tmp = 20
-----I am father progress-----
tmp = 20
my_vfork: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
Aborted (core dumped)

结论:vfork创建的子进程共享父进程资源

 运行程序出现问题:my_vfork: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
Aborted (core dumped)
vfork():同上返回两个值,区别在于vfork()子进程共享父进程的地址空间,即子进程运行在父进程的地址空间上,子进程对数据的修改父进程同样能看到。特别注意,使用vfork() 时子进程中需调用exec 或exit 父进程才可能被调度运行,如果在调用exec 或 exit之前子进程要依赖父进程的的某个行为,则会造成死锁。
a.out: cxa_atexit.c:100: __new_exitfn: Assertion `l != ((void *)0)' failed.
Aborted (core dumped)
这种错误的一个原因是由于子进程中没有调用exit 或 exec
在子进程中加入
exit(0);就可以运行正确。

3.3 exec族函数
作用:用来替换调用进程执行的程序。
在上面的例子中,在创建的子程序中任然和父进程有相同的代码空间,而实际中子程序都需要执行另外一个程序,
这种情况下,就可以使用exec族函数完全代替子进程的程序作为新程序。
#include<unistd.h>
exterm vooid **environ;
int execl(const char *path,cosnt char *arg,...);
int execlp(const char *file,cosnt char *arg,...);
int execle(const char *path,cosnt char *arg,...,char *const envp[]);
int execv(const char *path,char *cosnt argv[]);
int execvp(const char *file,char *cosnt argv[]);
int execvpe(const char *file,char *cosnt argv[],char *const envp[]);

后缀P:表示使用文件file做参数,如果file中包含"/"视作路径,否则在PATH环境变量所指的各个目录搜索文件。
后缀L:表示使用list形式传递参数,传入新程序的所有参数都是可变的,但是最后是以NULL结尾。
后缀V:传入的参数放入数组中

/*************************************************************************
	> File Name: my_execl.c
	> Author: 
	> Mail: 
	> Created Time: 2018年12月19日 星期三 14时43分17秒
 ************************************************************************/
//在本文件中创建子进程,然后调用new_progress 可执行文件

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>

int main(void)
{
	pid_t pid;

	pid = fork();
	if(pid < 0)
	{
		printf("Create progress failure\n");
		exit(1);
	}
	if(pid == 0)
	{
		//child progress
		printf("----I am child----\n");
		execl("./new_progress","new_progress",NULL);
		exit(2);
	}
	else
	{
		//father progress
		printf("----I am father progress----\n");
	}

	return 0;
}


/**********************************************************************
	> File Name: new_progress.c
	> Author: 
	> Mail: 
	> Created Time: 2018年12月19日 星期三 14时56分00秒
 *********************************************************************/

#include<stdio.h>

int main(void)
{
    printf("---- new_progress is runing ----\n");
    return 0;
}

运行结果:
----I am father progress----
----I am child----
---- new_progress is runing ----

猜你喜欢

转载自blog.csdn.net/weixin_41682169/article/details/85098079