多线程和多进程的管理

来源:互联网 发布:手机淘宝网店实名认证 编辑:程序博客网 时间:2024/06/15 22:11

多线程和多进程的管理

基础知识介绍

进程标识符

每个进程都有一个非负整型表示的唯一进程ID,除 了进程ID,每个进程还有一些其他的标识符。可通过下列函数来 返回。

pid_t getpid(void);//返回调用进程的进程ID pid_t getppid(void); //返回调用进程的父进程ID uid_t getuid(void); //返回调用进程的实际用户ID uid_t geteuid(void); //返回调用进程的有效用户IDgid_t getgid(void); //返回调用进程的实际组ID gid_t getegid(void);//返回调用进程的有效组ID

进程创建的时机

用户登录 为用户创建一个进程 作业调度 将作业装入内存,分配资源,创建进程 提供服务 服务于某种服务请求,创建一系列的后台服务进程 作业调度 由应用进程本身创建,让子进程和自己并发运行

进程的创建过程

  1. 取空白PCB,生成惟一的进程标识号。
  2. 为新进程分配必要的资源(包括程序段、数据段、栈段)。
  3. 初始化PCB。
  4. 将新进程的PCB插入就绪队列

Linux中进程的创建

Linux启动在内核态,在系统初始化结束时,初始进程启动一个核心进程(称为init),除了init进程外,Linux 中的所有进程都是由其他进程创建的。

使用系统调用fork()进行进程的创建。

子进程是父进程的映像,子进程除了进程的状态、标识 和与时间有关的控制项外,其余都与父进程相同。

fork系统调用

当进程调用fork创建子进程后,根据fork的返回值来判断:当
前执行的是父进程的程序段还是子进程的程序段。

返回值:
等于0,当前进程是子进程。 大于0,当前进程是父进程,返回值是子进程的ID。 等于-1,创建失败。

格式:

int pid_t fork(void);

头文件:

#include<sys/types.h> //提供pid_t的定义#include<unistd.h>

当一个程序中调用fork函数后,内核会完成如下工作:
1. 内核系统分配新的内存块和内核数据结构。
2. 复制原来的进程到新的进程。
3. 向运行进程集添加新的进程。
4. 将进程号返回给两个进程。

常见问题

  1. 父进程为什么要创建子进程?

    多用户操作系统、竞争资源、创建子进程争夺资源、父子进程一起从fork处继续执行。

  2. 父进程创建子进程后,子进程能不能执行不同的程序?

    答案是可以的,这种情况下,子进程从fork返回后要立即调 用exec系统调用来实现。

  3. 怎样才能使父进程在子进程结束之后才执行?

    调用wait系统调用来实现父子进程同步执行。

exec系统调用

用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。

当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行。

因为调用exec并不创建新进程,所以前后的进程ID并未改变。 exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈 段。

有六种不同的exec函数,它们被统称为exec函数。

execl (const char * filepath, const char* arg1, char* arg2......)execv (const char* filepath,char* argv[])execle(const char*filepath,const char*arg1,const char*arg2,....., char* cons envp[])execve (const char* filepath,char*argv[],char* const envp[]) execlp(const char *filename, const char *arg1, const char *arg2.....) execvp (const char * filename, char* argv[])

进程终止

  1. 进程正常结束 在进程执行期间调用exit系统调用。

  2. 进程的异常结束 在进程运行期间,由于出现错误或故障而被迫结束。

exit系统调用

格式:void exit(status)

参数status是调用进程终止时传递给父进程的值。如果调用进程 还有子进程,则将其所用子进程的父进程改为1号进程。

wait系统调用

wait函数用于使父进程阻塞,直到一个子进程结束。父进程调用
wait,该父进程可能会:
1. 阻塞
2. 带子进程的终止状态立即返回
3. 出错立即返回 格式:pid_t wait(int *status)

参数status是一个指向int类型的指针,用来保存被收集进程退出时的一 些状态。但如果我们对子进程是如何死掉的毫不在意,则pid=wait (NULL);
头文件:

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

线程相关知识

线程标识

就像每个进程都有一个进程ID一样,每个线程也有一个线程ID,
但线程ID只在它所属的进程环境中有效。
定义方法为:

pthread_t id;

线程创建

  • pthread库

    Linux下的多线程遵循POSIX线程接口,称为pthread。pthread是 一套用户级线程库,具有很好的移植性。但在linux上实现时,却使用了内 核级线程来完成,这样提高的线程的并发性。 Linux下的多线程程序, 需要使用头文件pthread.h,连接时需要使用库pthread。

    gcc example.c -lpthread -o example

pthread系统调用

pthread_create();//:创建一个线程。pthread_join();//:阻塞当前的线程,直到另外一个线程运行结束。pthread_exit();//:终止当前线程。pthread_cancel();:中断另外一个线程的运行。pthread_attr_init();//:初始化线程的属性。pthread_attr_setdetachstate()/;;:设置脱离状态的属性(决定这 个线程在终止时是否可以被结合)。pthread_attr_getdetachstate();//:获取脱离状态的属性。 pthread_attr_destroy();//:删除线程的属性。 pthread_kill();//:向线程发送一个信号。

pthread_create函数用来创建一个线程,它的原型为:

int pthread_create (    pthread_t *tidp,     pthread_attr_t *attr,     void*(*start_routine) (void *),     void *arg);

参数1:指向线程标识符的指针。
参数2:用来设置线程属性,若为NULL,则用默认属性。
参数3:新线程运行函数的起始地址。
参数4:运行函数的参数。

正确返回:0。线程标识存放在thread中
错误返回:非0的错误代码。

pthread_join 函数用来等待一个线程的结束,函数原型为:

int pthread_join (    pthread_t th,    void** thread_return );

参数1:为等待终止的子线程标识符。
参数2:用户定义的指针,它可以用来存储被等待线程的返回值。

这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止。

pthread_exit函数用来终止线程,函数原型为:

void pthread_exit (    void *_retval );

唯一的参数是函数的返回代码.
只要pthread_join中的第二个参数thread_return不是NULL, 这个值将被传递给thread_return。

相关练习

练习要求

1号进程创建2,3号两个进程
2号进程执行系统命令,ls,ps,cp等
3号进程创建4,5号两个进程
4号进程创建两个线程Thread1,Thread2。

Thread1:求(1~n)之间的素数
Thread2:生成Fibonacci序列

5号进程执行一个用户编写的可执行文件
每个进程输出自己的进程ID和父进程的进程ID,观察分析,并画出程序的进程树结构。

代码实现

#include <stdio.h>#include <sys/types.h> // tigong pid_t define#include <unistd.h>#include <sys/wait.h>#include <pthread.h>#include <math.h>#include <stdlib.h>void* thread_findss(){    int n=100;    printf("prime number:\n");    int i,j;    for(i=2;i<=n;i++)    {        for(j=2;j<i;j++)        {            if(i%j==0)            break;        }        if(j>=i)        printf("%d ",i);    }    printf("\n ");    pthread_exit(0);}int Fibo(int n){    if(n==1||n==2)        return 1;    return Fibo(n-1)+Fibo(n-2);}void* thread_fibonacci(){    int n=10;    printf("fibonacci:\n");    int i;    for(i=1;i<=n;i++)    {        printf("%d  ",Fibo(i));    }      printf("\n");      pthread_exit(0);}int main(int argc,char *argv[]){    pid_t pid2;    pid2=fork();    if(pid2<0)    {        fprintf(stderr,"2 fork failed");        exit(-1);    }    else if(pid2==0)  //son 2    {        // ls,ps,cp;       // printf("2 this is parent %d,child is %d\n",getppid(),getpid());            pid_t pid21;            pid21=fork();            if(pid21<0)            {                fprintf(stderr,"2 fork failed");                exit(-1);            }            else if(pid21==0)  //son 2            {                execlp("/bin/ls", "/bin/ls",NULL);                exit(0);            }            else{}            pid_t pid22;            pid22=fork();            if(pid22<0)            {                fprintf(stderr,"2 fork failed");                exit(-1);            }            else if(pid22==0)  //son 2            {                execlp("/bin/ps", "/bin/ps",NULL);                exit(0);            }            else{}        exit(0);    }    else{}    pid_t pid3;    pid3=fork();    if(pid3<0){    fprintf(stderr,"3 fork failed");    exit(-1);    }    else if(pid3==0)  //son 3    {       // printf("3 this is parent %d,child is %d\n",getppid(),getpid());        // creat 4,5        pid_t pid4;        pid4=fork();        if(pid4<0){        fprintf(stderr," 4 fork failed");        exit(-1);        }        else if(pid4==0)  //son 4        {           // printf("4 this is parent %d,child is %d\n",getppid(),getpid());            pthread_t id1;            pthread_attr_t attr1;            pthread_attr_init(&attr1);            pthread_create(&id1,&attr1,thread_findss,argv[1]);            pthread_join(id1,NULL);            pthread_t id2;            pthread_attr_t attr2;            pthread_attr_init(&attr2);            pthread_create(&id2,&attr2,thread_fibonacci,argv[1]);            pthread_join(id2,NULL);            exit(0);        }        else        {        }        pid_t pid5;        pid5=fork();        if(pid5<0){        fprintf(stderr," 5 fork failed");            exit(-1);        }        else if(pid5==0)  //son 5        {        //printf("5 this is parent %d,child is %d\n",getppid(),getpid());            execl("./sy1-help","sy1-help",NULL);            exit(0);        }        else        {        }         exit(0);   }   else   {   }    exit(0);    return 0;}

本博客内容到此结束,欢迎指正!

0 0
原创粉丝点击