Linux任务、进程和线程

参考书籍:《从实践中学嵌入式linux应用程序开发》(华清远见嵌入式学院)

资料下载:

参考链接:

形象化解释:

任务(task)是最抽象的,是一个一般性的术语,指由软件完成的一个活动。一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现。

进程(process)常常被定义为程序的执行。进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单 位。可以把一个进程看成是一个独立的程序,在内存中有其完备的数据空间和代码空间。一个进程所拥有的数据和变量只属于它自己。

线程(tread)则是某一进程中一路单独运行的程序。也就是说,线程存在于进程之中。一个进程由一个或多个线程构成,各线程共享相同的代码和全局数据,但各有其自己的堆栈。由于堆栈是每个线程一个,所以局部变量对每一线程来说是私有的。由于所有线程共享同样的代码和全局数据,它们比进程更紧密,比单独的进程间更趋向于相互作用,线程间的相互作用更容易些,因为它们本身就有某些供通信用的共享内存:进程的全局数据。

一个进程和一个线程最显著的区别是:线程有自己的全局数据。线程存在于进程中,因此一个进程的全局变量由所有的线程共享。由于线程共享同样的系统区域,操作系统分配给一个进程的资源对该进程的所有线程都是可用的,正如全局数据可供所有线程使用一样

进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。

进程和线程的关系: (1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。(3)处理机分给线程,即真正在处理机上运行的是线程。(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。

Linux进程:

实际上,当计算机开机的时候,内核(kernel)只建立了一个init进程。Linux kernel并不提供直接建立新进程的系统调用。剩下的所有进程都是init进程通过fork机制建立。新的进程要通过老的进程复制自身得到,这就是fork。fork是一个系统调用。进程存活于内存中,每个进程都在内存中分配有属于自己的一片空间 。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。

1)Linux操作系统中,每个进程都是通过唯一的进程ID标识的。进程ID 是一个非负数。每个进程除了进程ID外还有一些其它信息,都可以通过相应的函数获得。

2)一个进程除了有一个PID之外,还会有一个PPID(parent PID)来存储的父进程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是init进程。所以说,所有的进程也构成一个以init为根的树状结构。

3)主要的函数有:

pid_t getpid(void) :获得进程ID pid_t getppid(void) :获得进程父进程的IDpid_t getuid(void) :获得进程的实际用户IDpid_t geteuid(void) :获得进程的有效用户IDpid_t getgid(void) : 获得进程的实际组IDpid_t getegid(void) : 获得进程的有效组ID

fork()函数:

fork通常作为一个函数被调用。调用fork函数后,当前进程分裂为两个进程,一个是原来的父进程,另一个是刚创建的子进程。父进程调用fork后返回值是子进程的ID,子进程中返回值是0,若进程创建失败,只返回-1。失败原因一般是父进程拥有的子进程个数超过了规定限制(返回EAGAIN)或者内存不足(返回ENOMEM)。我们可以依据返回值判断进程,一般情况下调用fork函数后父子进程谁先执行是未定的,取决于内核所使用的调度算法。一般情况下os让所有进程享有同等执行权,除非某些进程优先级高。若有一个孤儿进程,即父进程先于子进程死去,子进程将会由init进程收养。

/*fork.c*/#include<sys/types.h>#include<unistd.h>#include<stdio.h>int main(){(pid < ( printf(“abc\n”);}编译后分别运行./fork 和 ./fork > test.txt 会得出不一样的答案。

fork()和vfork()函数之间的区别:

(1)fork():使用fork()创建一个子进程时,子进程只是完全复制父进程的资源。这样得到的子进程独立于父进程具有良好的并发性。 vfork(): 使用 vfor创建一个子进程时,操作系统并不将父进程的地址空间完全复制到子进程。而是子进程共享父进程的地址空间,即子进程完全运行在父进程的地址空间上。子进程对该地址空间中任何数据的修改同样为父进程所见。

(2)fork():父子进程执行顺序不定;vfork():保证子进程先运行,在调用exec或exit之前与父进程共享数据,在它调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

孤儿进程:如果一个子进程的父进程先于子进程结束,子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程。

守护进程:(daemon) 是指在后台运行,没有控制终端与之相连的进程。它独立于控制终端,通常周期性地执行某种任务 。

#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<string.h>#include<sys/types.h>#include<unistd.h>#include<sys/wait.h>int main(){pid_t pid;int i,fd;;pid = fork();if(pid < 0){printf();exit(0);}if(pid > 0){exit(0);}setsid();//创建一个新的会话组,并担任该会话组的组长chdir();//改变当前目录为根目录umask((i = 0;i < getdtablesize();i++){close(i);//关闭文件描述符 }(1){,O_CREAT|O_WRONLY|O_APPEND,0600))<0){printf();exit(0);}write(fd,buf,strlen(buf)+1);close(fd);sleep(10);}exit(0);}

tail –f /tmp/daemon.log

ps –ef|grep daemon

进程退出: exit 和 _exit 函数

(1)正常退出

a. 在main()函数中执行return 。renturn执行完后把控制权交给调用函数。

b.调用exit()函数,exit执行完后把控制权交给系统。

c.调用_exit()函数。

坦然接受生活给你的馈赠吧,不管是好的还是坏的。

Linux任务、进程和线程

相关文章:

你感兴趣的文章:

标签云: