精华内容
下载资源
问答
  • 深刻理解线程进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标 (二) 实验内容 以Linux系统进程线程机制为背景,掌握fork()和clone()系统调用的形式和功能,以及与其相适应...

    操作系统实验 进程与线程——Linux进程与线程通信


    (一) 实验目的
    深刻理解线程和进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标
    (二) 实验内容
    以Linux系统进程和线程机制为背景,掌握fork()和clone()系统调用的形式和功能,以及与其相适应的高级通讯方式。由fork派生的子进程之间通过pipe通讯,由clone创建的线程之间通过共享内存通讯,对于后者需要考虑互斥问题。
    以生产者/消费者问题为例,通过实验理解fork()和clone()两个系统调用的区别。程序要求能够创建4个进程或线程,其中包括两个生产者和两个消费者,生产者和消费者之间能够传递数据。
    (三) 实验准备
    fork系统调用
    clone系统调用
    pipe系统调用
    sem_wait(&s)和sem_post(&s)
    pthread_mutex_lock(&mutex)和pthread_mutex_unlock(&mutex)
    (四) 实验设计
    用pipe()创建一个管道文件,然后用fork()创建两个生产进程和两个消费进程,它们之间通过pipe()传递信息。
    用clone()创建四个轻进程(线程),用参数指明共享内存等资源,通过共享内存模拟生产消费问题,利用pthread_mutex_lock(), pthread_mutex_unlock()等函数实现对共享存储区访问的互斥。
    实验代码:
    fork系统调用实验代码:

    #include "sys/types.h"
    #include "sys/file.h"
    #include "unistd.h"
    char r_buf[4];  //读缓冲
    char w_buf[4];  //写缓冲
    int pipe_fd[2];
    pid_t pid1, pid2, pid3, pid4;
    int producer(int id);
    int consumer(int id);
    int main(int argc,char **argv)
    {  
    if(pipe(pipe_fd)<0)
    {
            printf("pipe create error \n");
            exit(-1);
    }
    else
    {
    printf("pipe is created successfully!\n");
    if((pid1=fork())==0)
          producer(1);
    if((pid2=fork())==0)
          producer(2);
    if((pid3=fork())==0)
          consumer(1);
    if((pid4=fork())==0)
          consumer(2);
        }
    close(pipe_fd[0]);  //需要加上这两句
    close(pipe_fd[1]);  //否这会有读者或者写者永远等待
        int i,pid,status;
    for(i=0;i<4;i++)
     pid=wait(&status);  
       exit(0);
    }
    
    int producer(int id)
    {
        printf("producer %d is running!\n",id);
        close(pipe_fd[0]);
        int i=0;
        for(i=1;i<10;i++)
        {
            sleep(3);
            if(id==1) //生产者1
                 strcpy(w_buf,"aaa\0");
            else  //生产者2
                 strcpy(w_buf,"bbb\0");
            if(write(pipe_fd[1],w_buf,4)==-1)
                printf("write to pipe error\n");    
        }
        close(pipe_fd[1]);
        printf("producer %d is over!\n",id);
        exit(id);
    }
    int consumer(int id)
    {
        close(pipe_fd[1]); 
        printf("producer %d is running!\n",id);
        if (id==1)  //消费者1
    strcpy(w_buf,"ccc\0");
        else  //消费者2
    strcpy(w_buf,"ddd\0");
        while(1)
        {
             sleep(1);
             strcpy(r_buf,"eee\0");
             if(read(pipe_fd[0],r_buf,4)==0)
                 break;     
             printf("consumer %d get %s, while the w_buf is %s\n",id,r_buf,w_buf);
        }
        close(pipe_fd[0]);
        printf("consumer %d is over!\n", id);
        exit(id);
    }
    

    编译:gcc fork.c -o fork.out 源文件:fork.c
    运行:./fork.out 编译后生成文件:fork.out
    结果:

    这里写图片描述
    clone系统调用实验代码:

    #include "sched.h"
    #include "pthread.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "semaphore.h"
    int producer(void * args);
    int consumer(void *args);
    pthread_mutex_t mutex;
    sem_t product;
    sem_t warehouse;
    char buffer[8][4];
    int bp=0;
    main(int argc,char** argv)
    {
      pthread_mutex_init(&mutex,NULL);
       sem_init(&product,0,0);
        sem_init(&warehouse,0,8);
       int clone_flag,arg,retval;
        char *stack;
        clone_flag=CLONE_VM|CLONE_SIGHAND|CLONE_FS|    CLONE_FILES;
        int i;
         for(i=0;i<2;i++)
         {  //创建四个线程
            arg = i;
            stack =(char*)malloc(4096); 
            retval=clone((void*)producer,&(stack[4095]),clone_flag,  (void*)&arg);
            stack =(char*)malloc(4096); 
            retval=clone((void*)consumer,&(stack[4095]),clone_flag,   (void*)&arg);
        //usleep(1000);
        usleep(1);
        }
        exit(1);
    }
    int producer(void* args)
    {
        int id = *((int*)args);
        int i;
        for(i=0;i<10;i++)
        {
           sleep(i+1);  //表现线程速度差别
            sem_wait(&warehouse);
            pthread_mutex_lock(&mutex);
            if(id==0)
                strcpy(buffer[bp],"aaa\0");
            else
                strcpy(buffer[bp],"bbb\0");
            bp++;
            printf("producer%d produce %s in %d\n",id,buffer[bp-1],bp-1);
            pthread_mutex_unlock(&mutex);
            sem_post(&product);
        }
        printf("producer%d is over!\n",id);
    }
    int consumer(void *args)
    {
        int id = *((int*)args);
        int i;
        for(i=0;i<10;i++)
        {
            sleep(10-i);  //表现线程速度差别
            sem_wait(&product);
            pthread_mutex_lock(&mutex);
            bp--;
            printf("consumer%d get %s in %d\n",id,buffer[bp],bp+1);
            strcpy(buffer[bp],"zzz\0");
            pthread_mutex_unlock(&mutex);
            sem_post(&warehouse);
        }
        printf("consumer%d is over!\n",id);
    }
    

    编译:gcc pthread clone.c -o clone.out 源文件clone.c
    运行:./clone.out 编译后文件:clone.out
    结果:(太长只截部分)
    这里写图片描述

    展开全文
  • 操作系统 课程设计任务书 实验题目 实验一进程与线程Linux 进程与线程通讯 实验目的 深刻理解线程与进程的概念掌握进程与线程在组成成分上的差别以及 与其相适应的通讯方式和应用目标 实验内容 以 Linux 系统进程和...
  • 进程与线程——Linux进程与线程通讯

    千次阅读 2013-04-06 23:38:42
    实验一 进程与线程——Linux进程与线程通讯 一、实验目的 深刻理解线程和进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标。 二、实验内容 1、以Linux系统进程和线程机制为...

    实验一 进程与线程——Linux进程与线程通讯

    一、实验目的

    深刻理解线程和进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标。

    二、实验内容

    1、以Linux系统进程和线程机制为背景,掌握fork()和clone()系统调用的形式和功能,以及与其相适应的高级通讯方式。由fork派生的子进程之间通过pipe通讯,由clone创建的线程之间通过共享内存通讯,对于后者需要考虑互斥问题。

    2、以生产者/消费者问题为例,通过实验理解fork()和clone()两个系统调用的区别。程序要求能够创建4个进程或线程,其中包括两个生产者和两个消费者,生产者和消费者之间能够传递数据。

    原书中代码 不再给出:遇到问题如下

    1.书中有打印错误  CLONE_SIGNAND 应为 CLONE_SIGHAND

    2.在mian中,创建线程的代码段;书中有错误;

    int clone_flag,arg,retval;
    	char *stack;03.
    	clone_flag = CLONE_VM|CLONE_SIGNAND|CLONE_FS|CLONE_FILES;
    	int i;
    	for(i=0;i<2;i++)
    	{
    		arg=i;
    		stack=(char*)malloc(4096);
    		retval = clone((void*)producer,&(stack[4095]),clone_flag,(void*)&arg);
    		stack=(char*)malloc(4096);
    		retval = clone((void*)consumer,&(stack[4095]),clone_flag,(void*)&arg);
    	}


    分析:
    声明变量 *arg,在循环中 把 arg=i; 调用 clone时, 传入参数 &arg;

    虽然 arg每次循环后 ,值不一样,但是 传入的参数&arg 即arg的地址没有变化,所以 作者原意 要创建两个 生产者和两个消费者的线程, 在实际运行会发现 结果只能创建出一个生产者和一个消费者。

    修改后代码为:

    int clone_flag,*arg, args[2] = {0, 1},retval;
    	char *stack;
    	clone_flag = CLONE_VM|CLONE_SIGHAND|CLONE_FS|CLONE_FILES;
    	int i;
    	for(i=0;i<2;i++)
    	{
    		arg = &args[i];
    		stack=(char*)malloc(4096);
    		retval = clone((void*)producer,&(stack[4095]),clone_flag,(void*)arg);
    		stack=(char*)malloc(4096);
    		retval = clone((void*)consumer,&(stack[4095]),clone_flag,(void*)arg);
    	}


    完整代码如下:

    #include "sched.h"
    #include "pthread.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    #include "semaphore.h"
     
    int producer(void *args);
    int consumer(void *args);
    pthread_mutex_t mutex;
    sem_t product;
    sem_t warehouse;
    
    char buffer[8][4];
    int bp=0;
    
    int main(int argc,char **argv)
    {
    	pthread_mutex_init(&mutex,NULL);
    	sem_init(&product,0,0);
    	sem_init(&warehouse,0,8);
    	int clone_flag,*arg, args[2] = {0, 1},retval;
    	char *stack;
    	clone_flag = CLONE_VM|CLONE_SIGHAND|CLONE_FS|CLONE_FILES;
    	int i;
    	for(i=0;i<2;i++)
    	{
    		arg = &args[i];
    		stack=(char*)malloc(4096);
    		retval = clone((void*)producer,&(stack[4095]),clone_flag,(void*)arg);
    		stack=(char*)malloc(4096);
    		retval = clone((void*)consumer,&(stack[4095]),clone_flag,(void*)arg);
    	}
    	exit(1);
    }
    
    int producer(void *args)
    {
    	int id=*((int*)args);
    	int i;
    	for(i=0;i<10;i++)
    	{
    		sleep(i+1);
    		sem_wait(&warehouse);
    		pthread_mutex_lock(&mutex);
    		if(id==0)
    			strcpy(buffer[bp],"aaa\0");
    		else
    			strcpy(buffer[bp],"bbb\0");
    		bp++;
    		printf("producer %d produce %s in %d\n",id,buffer[bp-1],bp-1);
    		pthread_mutex_unlock(&mutex);
    		sem_post(&product);
    	}
    	printf("producer %d is over!\n",id);
    }
    
    int consumer(void *args)
    {
    	int id=*((int*)args);
    	int i;
    	for(i=0;i<10;i++)
    	{
    		sleep(10-i);
    		sem_wait(&product);
    		pthread_mutex_lock(&mutex);
    		bp--;
    		printf("consumer %d get %s in %d\n",id,buffer[bp],bp);
    		strcpy(buffer[bp],"zzz\0");
    		pthread_mutex_unlock(&mutex);
    		sem_post(&warehouse);
    	}
    	printf("consumer %d is over!\n",id);
    }


     

    展开全文
  • Linux进程与线程的区别

    千次阅读 2019-12-12 16:28:34
    Linux进程与线程的区别 ** 本文较长,耐心阅读,必有收获! 进程与线程的区别,早已经成为了经典问题。自线程概念诞生起,关于这个问题的讨论就没有停止过。无论是初级程序员,还是资深专家,都应该考虑过这个问题,...

    **

    Linux进程与线程的区别

    **

    本文较长,耐心阅读,必有收获!

    进程与线程的区别,早已经成为了经典问题。自线程概念诞生起,关于这个问题的讨论就没有停止过。无论是初级程序员,还是资深专家,都应该考虑过这个问题,只是层次角度不同罢了。一般程序员而言,搞清楚二者的概念,在工作实际中去运用成为了焦点。而资深工程师则在考虑系统层面如何实现两种技术及其各自的性能和实现代价。以至于到今天,Linux内核还在持续更新完善(关于进程和线程的实现模块也是内核完善的任务之一)。

    本文将以一个从事Linux平台系统开发的程序员角度描述这个经典问题。本文素材全部来源于工作实践经验与知识规整,若有疏漏或不正之处,敬请读者慷慨指出。

    0.首先,简要了解一下进程和线程。对于操作系统而言,进程是核心之核心,整个现代操作系统的根本,就是以进程为单位在执行任务。系统的管理架构也是基于进程层面的。在按下电源键之后,计算机就开始了复杂的启动过程,此处有一个经典问题:当按下电源键之后,计算机如何把自己由静止启动起来的?本文不讨论系统启动过程,请读者自行科普。操作系统启动的过程简直可以描述为上帝创造万物的过程,期初没有世界,但是有上帝,是上帝创造了世界,之后创造了万物,然后再创造了人,然后塑造了人的七情六欲,再然后人类社会开始遵循自然规律繁衍生息。。。操作系统启动进程的阶段就相当于上帝造人的阶段。本文讨论的全部内容都是“上帝造人”之后的事情。第一个被创造出来的进程是0号进程,这个进程在操作系统层面是不可见的,但它存在着。0号进程完成了操作系统的功能加载与初期设定,然后它创造了1号进程(init),这个1号进程就是操作系统的“耶稣”。1号进程是上帝派来管理整个操作系统的,所以在用pstree查看进程树可知,1号进程位于树根。再之后,系统的很多管理程序都以进程身份被1号进程创造出来,还创造了与人类沟通的桥梁——shell。从那之后,人类可以跟操作系统进行交流,可以编写程序,可以执行任务。。。

    而这一切,都是基于进程的。每一个任务(进程)被创建时,系统会为他分配存储空间等必要资源,然后在内核管理区为该进程创建管理节点,以便后来控制和调度该任务的执行。

    进程真正进入执行阶段,还需要获得CPU的使用权,这一切都是操作系统掌管着,也就是所谓的调度,在各种条件满足(资源与CPU使用权均获得)的情况下,启动进程的执行过程。

    除CPU而外,一个很重要的资源就是存储器了,系统会为每个进程分配独有的存储空间,当然包括它特别需要的别的资源,比如写入时外部设备是可使用状态等等。有了上面的引入,我们可以对进程做一个简要的总结:

    进程,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。它的执行需要系统分配资源创建实体之后,才能进行。

    随着技术发展,在执行一些细小任务时,本身无需分配单独资源时(多个任务共享同一组资源即可,比如所有子进程共享父进程的资源),进程的实现机制依然会繁琐的将资源分割,这样造成浪费,而且还消耗时间。后来就有了专门的多任务技术被创造出来——线程。

    线程的特点就是在不需要独立资源的情况下就可以运行。如此一来会极大节省资源开销,以及处理时间。

    1.好了,前面的一段文字是简要引入两个名词,即进程和线程。本文讨论目标是解释清楚进程和线程的区别,关于二者的技术实现,请读者查阅相关资料。

    下面我们开始重点讨论本文核心了。从下面几个方面阐述进程和线程的区别。

    1).二者的相同点

    2).实现方式的差异

    3).多任务程序设计模式的区别

    4).实体间(进程间,线程间,进线程间)通信方式的不同

    5).控制方式的异同

    6).资源管理方式的异同

    7).个体间辈分关系的迥异

    8).进程池与线程池的技术实现差别

    接下来我们就逐个进行解释。

    1).二者的相同点

    无论是进程还是线程,对于程序员而言,都是用来实现多任务并发的技术手段。二者都可以独立调度,因此在多任务环境下,功能上并无差异。并且二者都具有各自的实体,是系统独立管理的对象个体。所以在系统层面,都可以通过技术手段实现二者的控制。而且二者所具有的状态都非常相似。而且,在多任务程序中,子进程(子线程)的调度一般与父进程(父线程)平等竞争。

    其实在Linux内核2.4版以前,线程的实现和管理方式就是完全按照进程方式实现的。在2.6版内核以后才有了单独的线程实现。

    在这里插入图片描述
    在这里插入图片描述

    2).实现方式的差异

    进程是资源分配的基本单位,线程是调度的基本单位。

    这句经典名言已流传数十年,各种操作系统教材都可见此描述。确实如此,这就是二者的显著区别。读者请注意“基本”二字。相信有读者看到前半句的时候就在心里思考,“进程岂不是不能调度?”,非也!进程和线程都可以被调度,否则多进程程序该如何运行呢!

    只是,线程是更小的可以调度的单位,也就是说,只要达到线程的水平就可以被调度了,进程自然可以被调度。它强调的是分配资源时的对象必须是进程,不会给一个线程单独分配系统管理的资源。若要运行一个任务,想要获得资源,最起码得有进程,其他子任务可以以线程身份运行,资源共享就行了。

    简而言之,进程的个体间是完全独立的,而线程间是彼此依存的。多进程环境中,任何一个进程的终止,不会影响到其他进程。而多线程环境中,父线程终止,全部子线程被迫终止(没有了资源)。而任何一个子线程终止一般不会影响其他线程,除非子线程执行了exit()系统调用。任何一个子线程执行exit(),全部线程同时灭亡。

    其实,也没有人写出只有线程而没有进程的程序。多线程程序中至少有一个主线程,而这个主线程其实就是有main函数的进程。它是整个程序的进程,所有线程都是它的子线程。我们通常把具有多线程的主进程称之为主线程。

    从系统实现角度讲,进程的实现是调用fork系统调用:

    pid_t fork(void);

    线程的实现是调用clone系统调用:

    int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, …

    /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */

    );

    其中,fork()是将父进程的全部资源复制给了子进程。而线程的clone只是复制了一小部分必要的资源。在调用clone时可以通过参数控制要复制的对象。可以说,fork实现的是clone的加强完整版。当然,后来操作系统还进一步优化fork实现——写时复制技术。在子进程需要复制资源(比如子进程执行写入动作更改父进程内存空间)时才复制,否则创建子进程时先不复制。

    实际中,编写多进程程序时采用fork创建子进程实体。而创建线程时并不采用clone系统调用,而是采用线程库函数。常用线程库有Linux-Native线程库和POSIX线程库。其中应用最为广泛的是POSIX线程库。因此读者在多线程程序中看到的是pthread_create而非clone。

    我们知道,库是建立在操作系统层面上的功能集合,因而它的功能都是操作系统提供的。由此可知,线程库的内部很可能实现了clone的调用。不管是进程还是线程的实体,都是操作系统上运行的实体。

    最后,我们说一下vfork() 。这也是一个系统调用,用来创建一个新的进程。它创建的进程并不复制父进程的资源空间,而是共享,也就说实际上vfork实现的是一个接近线程的实体,只是以进程方式来管理它。并且,vfork()的子进程与父进程的运行时间是确定的:子进程“结束”后父进程才运行。请读者注意“结束”二字。并非子进程完成退出之意,而是子进程返回时。一般采用vfork()的子进程,都会紧接着执行execv启动一个全新的进程,该进程的进程空间与父进程完全独立不相干,所以不需要复制父进程资源空间。此时,execv返回时父进程就认为子进程“结束”了,自己开始运行。实际上子进程继续在一个完全独立的空间运行着。举个例子,比如在一个聊天程序中,弹出了一个视频播放器。你说视频播放器要继承你的聊天程序的进程空间的资源干嘛?莫非视频播放器想要窥探你的聊天隐私不成?懂了吧!

    3).多任务程序设计模式的区别

    由于进程间是独立的,所以在设计多进程程序时,需要做到资源独立管理时就有了天然优势,而线程就显得麻烦多了。比如多任务的TCP程序的服务端,父进程执行accept()一个客户端连接请求之后会返回一个新建立的连接的描述符DES,此时如果fork()一个子进程,将DES带入到子进程空间去处理该连接的请求,父进程继续accept等待别的客户端连接请求,这样设计非常简练,而且父进程可以用同一变量(val)保存accept()的返回值,因为子进程会复制val到自己空间,父进程再覆盖此前的值不影响子进程工作。但是如果换成多线程,父线程就不能复用一个变量val多次执行accept()了。因为子线程没有复制val的存储空间,而是使用父线程的,如果子线程在读取val时父线程接受了另一个客户端请求覆盖了该值,则子线程无法继续处理上一次的连接任务了。改进的办法是子线程立马复制val的值在自己的栈区,但父线程必须保证子线程复制动作完成之后再执行新的accept()。但这执行起来并不简单,因为子线程与父线程的调度是独立的,父线程无法知道子线程何时复制完毕。这又得发生线程间通信,子线程复制完成后主动通知父线程。这样一来父线程的处理动作必然不能连贯,比起多进程环境,父线程显得效率有所下降。

    PS:这里引述一个知名的面试问题:多进程的TCP服务端,能否互换fork()与accept()的位置?
    通过fork()创建子进程时,子进程继承父进程环境和上下文的大部分内容的拷贝,其中就包括文件描述符表。

    (1)对于父进程在fork()之前所建立的连接,子进程都会继承,与父进程共享相同的文件偏移量。系统文件表位于系统空间中,不会被fork()复制,但是系统文件表中的条目会保存指向它的文件描述符表的计数,

    fork()时需要对这个计数进行维护,以体现子进程对应的新的文件描述符表也指向它。程序关闭文件时,也是将系统文件表条目内部的计数减一,当计数值减为0时,将其删除。

    (2)对于父进程在fork()之后建立连接,此时还没有打开文件描述符,所以子进程没有继承到文件描述符,子进程将会自己建立一条连接,不与父进程共享偏移量,而此时父进程也会建立一条连接,并且文件描述符表中的计数器会增加,当子进程结束后,文件计数器减一,而父进程一直执行,但不会为零,所以这个文件描述符会一直存在,占用资源。

    所以在faccept之前fork()后要在父进程中关闭accept的描述符,并且在fork子进程中关闭listen的描述符;而在accept后调用fork()则只需要在子进程中关闭listen描述符,父进程中不做处理。

    关于资源不独立,看似是个缺点,但在有的情况下就成了优点。多进程环境间完全独立,要实现通信的话就得采用进程间的通信方式,它们通常都是耗时间的。而线程则不用任何手段数据就是共享的。当然多个子线程在同时执行写入操作时需要实现互斥,否则数据就写“脏”了。

    4).实体间(进程间,线程间,进线程间)通信方式的不同

    进程间的通信方式有这样几种:

    A.共享内存 B.消息队列 C.信号量 D.有名管道 E.无名管道 F.信号

    G.文件 H.socket

    线程间的通信方式上述进程间的方式都可沿用,且还有自己独特的几种:

    A.互斥量 B.自旋锁 C.条件变量 D.读写锁 E.线程信号

    G.全局变量

    值得注意的是,线程间通信用的信号不能采用进程间的信号,因为信号是基于进程为单位的,而线程是共属于同一进程空间的。故而要采用线程信号。

    综上,进程间通信手段有8种。线程间通信手段有13种。

    而且,进程间采用的通信方式要么需要切换内核上下文,要么要与外设访问(有名管道,文件)。所以速度会比较慢。而线程采用自己特有的通信方式的话,基本都在自己的进程空间内完成,不存在切换,所以通信速度会较快。也就是说,进程间与线程间分别采用的通信方式,除了种类的区别外,还有速度上的区别。

    另外,进程与线程之间穿插通信的方式,除信号以外其他进程间通信方式都可采用。
    线程有内核态线程与用户级线程,相关知识请参看我的另一篇博文《Linux线程的实质》。

    5).控制方式的异同

    进程与线程的身份标示ID管理方式不一样,进程的ID为pid_t类型,实际为一个int型的变量(也就是说是有限的):

    /usr/include/unistd.h:260:typedef __pid_t pid_t;

    /usr/include/bits/types.h:126:# define __STD_TYPE typedef

    /usr/include/bits/types.h:142:__STD_TYPE __PID_T_TYPE __pid_t;

    /usr/include/bits/typesizes.h:53:#define __PID_T_TYPE __S32_TYPE

    /usr/include/bits/types.h💯#define __S32_TYPE int

    在全系统中,进程ID是唯一标识,对于进程的管理都是通过PID来实现的。每创建一个进程,内核去中就会创建一个结构体来存储该进程的全部信息:

    注:下述代码来自 Linux内核3.18.1

    include/linux/sched.h:1235:struct task_struct {

        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    
        void *stack;
    

        pid_t pid;
    
        pid_t tgid;
    

    };

    每一个存储进程信息的节点也都保存着自己的PID。需要管理该进程时就通过这个ID来实现(比如发送信号)。当子进程结束要回收时(子进程调用exit()退出或代码执行完),需要通过wait()系统调用来进行,未回收的消亡进程会成为僵尸进程,其进程实体已经不复存在,但会虚占PID资源,因此回收是有必要的。

    线程的ID是一个long型变量:

    /usr/include/bits/pthreadtypes.h:60:typedef unsigned long int pthread_t;

    它的范围大得多,管理方式也不一样。线程ID一般在本进程空间内作用就可以了,当然系统在管理线程时也需要记录其信息。其方式是,在内核创建一个内核态线程与之对应,也就是说每一个用户创建的线程都有一个内核态线程对应。但这种对应关系不是一对一,而是多对一的关系,也就是一个内核态线程可以对应着多个用户级线程。还是请读者参看《Linux线程的实质》普及相关概念。此处贴出blog地址:

    http://my.oschina.net/cnyinlinux/blog/367910

    对于线程而言,若要主动终止需要调用pthread_exit() ,主线程需要调用pthread_join()来回收(前提是该线程没有被detached,相关概念请查阅线程的“分离属性”)。像线发送线程信号也是通过线程ID实现的。

    6).资源管理方式的异同

    进程本身是资源分配的基本单位,因而它的资源都是独立的,如果有多进程间的共享资源,就要用到进程间的通信方式了,比如共享内存。共享数据就放在共享内存去,大家都可以访问,为保证数据写入的安全,加上信号量一同使用。一般而言,共享内存都是和信号量一起使用。消息队列则不同,由于消息的收发是原子操作,因而自动实现了互斥,单独使用就是安全的。

    线程间要使用共享资源不需要用共享内存,直接使用全局变量即可,或者malloc()动态申请内存。显得方便直接。而且互斥使用的是同一进程空间内的互斥量,所以效率上也有优势。

    实际中,为了使程序内资源充分规整,也都采用共享内存来存储核心数据。不管进程还是线程,都采用这种方式。原因之一就是,共享内存是脱离进程的资源,如果进程发生意外终止的话,共享内存可以独立存在不会被回收(是否回收由用户编程实现)。进程的空间在进程崩溃的那一刻也被系统回收了。虽然有coredump机制,但也只能是有限的弥补。共享内存在进程down之后还完整保存,这样可以拿来分析程序的故障原因。同时,运行的宝贵数据没有丢失,程序重启之后还能继续处理之前未完成的任务,这也是采用共享内存的又一大好处。

    总结之,进程间的通信方式都是脱离于进程本身存在的,是全系统都可见的。这样一来,进程的单点故障并不会损毁数据,当然这不一定全是优点。比如,进程崩溃前对信号量加锁,崩溃后重启,然后再次进入运行状态,此时直接进行加锁,可能造成死锁,程序再也无法继续运转。再比如,共享内存是全系统可见的,如果你的进程资源被他人误读误写,后果肯定也是你不想要的。所以,各有利弊,关键在于程序设计时如何考量,技术上如何规避。这说起来又是编程技巧和经验的事情了。

    7).个体间辈分关系的迥异

    进程的备份关系森严,在父进程没有结束前,所有的子进程都尊从父子关系,也就是说A创建了B,则A与B是父子关系,B又创建了C,则B与C也是父子关系,A与C构成爷孙关系,也就是说C是A的孙子进程。在系统上使用pstree命令打印进程树,可以清晰看到备份关系。

    多线程间的关系没有那么严格,不管是父线程还是子线程创建了新的线程,都是共享父线程的资源,所以,都可以说是父线程的子线程,也就是只存在一个父线程,其余线程都是父线程的子线程。

    8).进程池与线程池的技术实现差别

    我们都知道,进程和线程的创建时需要时间的,并且系统所能承受的进程和线程数也是有上限的,这样一来,如果业务在运行中需要动态创建子进程或线程时,系统无法承受不能立即创建的话,必然影响业务。综上,聪明的程序员发明了一种新方法——池。

    在程序启动时,就预先创建一些子进程或线程,这样在需要用时直接使唤。这就是老人口中的“多生孩子多种树”。程序才开始运行,没有那么多的服务请求,必然大量的进程或线程空闲,这时候一般让他们“冬眠”,这样不耗资源,要不然一大堆孩子的口食也是个负担啊。对于进程和线程而言,方式是不一样的。另外,当你有了任务,要分配给那些孩子的时候,手段也不一样。下面就分别来解说。

    进程池

    首先创建了一批进程,就得管理,也就是你得分开保存进程ID,可以用数组,也可用链表。建议用数组,这样可以实现常数内找到某个线程,而且既然做了进程池,就预先估计好了生产多少进程合适,一般也不会再动态延展。就算要动态延展,也能预估范围,提前做一个足够大的数组。不为别的,就是为了快速响应。本来错进程池的目的也是为了效率。

    接下来就要让闲置进程冬眠了,可以让他们pause()挂起,也可用信号量挂起,还可以用IPC阻塞,方法很多,分析各自优缺点根据实际情况采用就是了。

    然后是分配任务了,当你有任务的时候就要让他干活了。唤醒了进程,让它从哪儿开始干呢?肯定得用到进程间通信了,比如信号唤醒它,然后让它在预先指定的地方去读取任务,可以用函数指针来实现,要让它干什么,就在约定的地方设置代码段指针。这也只是告诉了它怎么干,还没说干什么(数据条件),再通过共享内存把要处理的数据设置好,这也子进程就知道怎么做了。干完之后再来一次进程间通信然后自己继续冬眠,父进程就知道孩子干完了,收割成果。

    最后结束时回收子进程,向各进程发送信号唤醒,改变激活状态让其主动结束,然后逐个wait()就可以了。

    线程池

    线程池的思想与上述类似,只是它更为轻量级,所以调度起来不用等待额外的资源。

    要让线程阻塞,用条件变量就是了,需要干活的时候父线程改变条件,子线程就被激活。

    线程间通信方式就不用赘述了,不用繁琐的通信就能达成,比起进程间效率要高一些。

    线程干完之后自己再改变条件,这样父线程也就知道该收割成果了。

    整个程序结束时,逐个改变条件并改变激活状态让子线程结束,最后逐个回收即可。

    展开全文
  • java进程线程通信方法以及进程与线程的区别

     进程间通信的方法

    主要有以下几种:

       (1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
      (2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
      (3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
      (4)消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺
      (5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
      (6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
      (7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

      (8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

    而在java中我们实现多线程间通信则主要采用"共享变量"和"管道流"这两种方法
    方法一 通过访问共享变量的方式(注:需要处理同步问题)
    方法二 通过管道流

    其中方法一有两种实现方法,即
    方法一a)通过内部类实现线程的共享变量

      
    /** 
     * 通过内部类实现线程的共享变量 
     * 
     */  
    public class Innersharethread {  
        public static void main(String[] args) {  
            Mythread mythread = new Mythread();  
            mythread.getThread().start();  
            mythread.getThread().start();  
            mythread.getThread().start();  
            mythread.getThread().start();  
        }  
    }  
    class Mythread {  
        int index = 0;  
      
        private class InnerThread extends Thread {  
            public synchronized void run() {  
                while (true) {  
                    System.out.println(Thread.currentThread().getName()  
                            + "is running and index is " + index++);  
                }  
            }  
        }  
      
        public Thread getThread() {  
            return new InnerThread();  
        }  
    }
    b)通过实现Runnable接口实现线程的共享变量
    代码如下:

    
    /**
     * 通过实现Runnable接口实现线程的共享变量
     
     */
    public class Interfacaesharethread {
    	public static void main(String[] args) {
    		Mythread mythread = new Mythread();
    		new Thread(mythread).start();
    		new Thread(mythread).start();
    		new Thread(mythread).start();
    		new Thread(mythread).start();
    	}
    }
    
    /* 实现Runnable接口 */
    class Mythread implements Runnable {
    	int index = 0;
    
    	public synchronized void run() {
    		while (true)
    			System.out.println(Thread.currentThread().getName() + "is running and
                            the index is " + index++);
    	}
    }
    方法二(通过管道流):
    代码如下:

    public class CommunicateWhitPiping {
    	public static void main(String[] args) {
    		/**
    		 * 创建管道输出流
    		 */
    		PipedOutputStream pos = new PipedOutputStream();
    		/**
    		 * 创建管道输入流
    		 */
    		PipedInputStream pis = new PipedInputStream();
    		try {
    			/**
    			 * 将管道输入流与输出流连接 此过程也可通过重载的构造函数来实现
    			 */
    			pos.connect(pis);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		/**
    		 * 创建生产者线程
    		 */
    		Producer p = new Producer(pos);
    		/**
    		 * 创建消费者线程
    		 */
    		Consumer c = new Consumer(pis);
    		/**
    		 * 启动线程
    		 */
    		p.start();
    		c.start();
    	}
    }
    
    /**
     * 生产者线程(与一个管道输入流相关联)
     * 
     */
    class Producer extends Thread {
    	private PipedOutputStream pos;
    
    	public Producer(PipedOutputStream pos) {
    		this.pos = pos;
    	}
    
    	public void run() {
    		int i = 8;
    		try {
    			pos.write(i);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    /**
     * 消费者线程(与一个管道输入流相关联)
     * 
     */
    class Consumer extends Thread {
    	private PipedInputStream pis;
    
    	public Consumer(PipedInputStream pis) {
    		this.pis = pis;
    	}
    
    	public void run() {
    		try {
    			System.out.println(pis.read());
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    线程间的通信方式

    锁机制:包括互斥锁、条件变量、读写锁
       *互斥锁提供了以排他方式防止数据结构被并发修改的方法。
       *读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
       *条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
    信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
    信号机制(Signal):类似进程间的信号处理
        线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

    进程与线程的区别和联系

    进程概念

      进程是表示资源分配的基本单位,又是调度运行的基本单位。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。所以,进程是系统中的并发执行的单位。
              在Mac、Windows NT等采用微内核结构的操作系统中,进程的功能发生了变化:它只是资源分配的单位,而不再是调度运行的单位。在微内核系统中,真正调度运行的基本单位是线程。因此,实现并发功能的单位是线程。

    线程概念

      线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行。操作系统提供线程就是为了方便而有效地实现这种并发性

    引入线程的好处

    (1)易于调度
    (2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
    (3)开销少。创建线程比创建进程要快,所需开销很少。。
    (4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。

    进程和线程的关系

    (1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
    (2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
    (3)处理机分给线程,即真正在处理机上运行的是线程。
    (4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
            处理机管理是操作系统的基本管理功能之一,它所关心的是处理机的分配问题。也就是说把CPU(中央处理机)的使用权分给某个程序,通常把这个正准备进入内存的程序称为作业,当这个作业进入内存后我们把它称为进程
    自从60年代提出进程概念,在操作系统中一直都是以进程作为能独立运行的基本单位的。直到80年代中期,人们又提出了比进程更小的能独立运行的基本单位 ——线程;试图用它来提高系统内程序并发执行的速度,从而可进一步提高系统的吞吐量。近几年,线程概念已得到了广泛应用,不仅在新推出的操作系统中,大多 都已引入了线程概念,而且在新推出的数据库管理系统和其它应用软件中,也都纷纷引入了线程,来改善系统的性能。
            如果说,在操作系统中引入进程的目的,是为了使多个程序并发执行,以改善资源利用率及提高系统的吞吐量;那么,在操作系统中再引入线程则是为了减少程序并 发执行时所付出的时空开销,使操作系统具有更好的并发性。为了说明这一点,我们首先回顾进程的两个基本属性:
    (1)进程是一个可拥有资源的独立单位;
    (2)进程同时又是——个可以独立调度和分派的基本单位。
    正是由于进程具有这两个基本属性,才使之成为一个能独立运行的基本单位,从而也就构成了进程并发执行的基础。
    然而为使程序能并发执行,系统还必须进行以下的一系列操作:
    (1)创建进程。系统在创建进程时,必须为之分配其所必需的、除处理机以外的所有资源。如内存空间、I/0设备以及建立相应的PCB。
    (2)撤消进程。系统在撤消进程时,又必须先对这些资源进行回收操作,然后再撤消PCB。
    (3)进程切换。在对进程进行切换时,由于要保留当前进程的CPU环境和设置新选中进程的CPU环境,为此需花费不少处理机时间。
    简言之,由于进程是一个资源拥有者,因而在进程的创建、撤消和切换中,系统必须为之付出较大的时空开销。也正因为如此,在系统中所设置的进程数目不宜过多,进程切换的频率也不宜太高,但这也就限制了并发程度的进一步提高。
           如何能使多个程序更好地并发执行,同时又尽量减少系统的开销,已成为近年来设计操作系统时所追求的重要目标。于是,有不少操作系统的学者们想到,可否将进 程的上述属性分开,由操作系统分开来进行处理。即对作为调度和分派的基本单位,不同时作为独立分配资源的单位,以使之轻装运行;而对拥有资源的基本单位, 又不频繁地对之进行切换。正是在这种思想的指导下,产生了线程概念。
           在引入线程的操作系统中,线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源 (如程序计数器、一组寄存器和栈),但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程;同一进程中的多个线程 之间可以并发执行。由于线程之间的相互制约,致使线程在运行中也呈现出间断性。相应地,线程也同样有就绪、阻塞和执行三种基本状态,有的系统中线程还有终 止状态。

    线程与进程的比较

            线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进程都有若干个线程,至少需要一个线程。下面,我们从调度、并发性、 系统开销、拥有资源等方面,来比较线程与进程。

    1.调度

           在传统的操作系统中,拥有资源的基本单位和独立调度、分派的基本单位都是进程。而在引入线程的操作系统中,则把线程作为调度和分派的基本单位。而把进程作 为资源拥有的基本单位,使传统进程的两个属性分开,线程便能轻装运行,从而可显著地提高系统的并发程度。在同一进程中,线程的切换不会引起进程的切换,在 由一个进程中的线程切换到另一个进程中的线程时,将会引起进程的切换。

    2.并发性

           在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间,亦可并发执行,因而使操作系统具有更好的并发性,从而能更有效地使 用系统资源和提高系统吞吐量。例如,在一个未引入线程的单CPU操作系统中,若仅设置一个文件服务进程,当它由于某种原因而被阻塞时,便没有其它的文件服 务进程来提供服务。在引入了线程的操作系统中,可以在一个文件服务进程中,设置多个服务线程,当第一个线程等待时,文件服务进程中的第二个线程可以继续运 行;当第二个线程阻塞时,第三个线程可以继续执行,从而显著地提高了文件服务的质量以及系统吞吐量。

    3.拥有资源

           不论是传统的操作系统,还是设有线程的操作系统,进程都是拥有资源的一个独立单位,它可以拥有自己的资源。一般地说,线程自己不拥有系统资源(也有一点必 不可少的资源),但它可以访问其隶属进程的资源。亦即,一个进程的代码段、数据段以及系统资源,如已打开的文件、I/O设备等,可供问一进程的其它所有线 程共享。

    4.系统开销

            由于在创建或撤消进程时,系统都要为之分配或回收资源,如内存空间、I/o设备等。因此,操作系统所付出的开销将显著地大于在创建或撤消线程时的开销。类 似地,在进行进程切换时,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置。而线程切换只须保存和设置少量寄存器的内容,并 不涉及存储器管理方面的操作。可见,进程切换的开销也远大于线程切换的开销。此外,由于同一进程中的多个线程具有相同的地址空间,致使它们之间的同步和通信的实现,也变得比较容易。在有的系统中,线程的切换、同步和通信都无须

    http://www.cnblogs.com/losing-1216/p/5083097.html

    https://my.oschina.net/u/248570/blog/53226

    展开全文
  • #Linux#进程通信# 进程与线程

    万次阅读 2019-12-27 13:52:24
    进程的概念 进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放。可以认为进程是一个程序的一次...在当代面向线程设计的计算机结构中,进程...
  • 进程的同步通信,进程与线程同步的区别,进程与线程通信的区别 2013-08-10 15:45:31 这两天看进程的同步通信,看了几本书上的介绍,也从网上搜了很多资料,越看越迷惑,被这几个问题搞得很纠结。 进程...
  • Linux进程/线程通信方式

    千次阅读 2013-07-15 08:45:55
    Linux系统中的进程通信方式主要以下几种: 同一主机上的进程通信方式  * UNIX进程通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal)  * System V进程通信方式:包括信号量(Semaphore), 消息队列...
  • 当一个程序内有多个线程被拆分出用以执行多个流时,这些线程就会在它们之间共享特定的资源(如,内存地址空间、打开的文件),以使拆分开销最小化,并避免大量高成本的IPC(进程通信)通道。 线程与进程之间的ID ...
  • 一,进程与线程 进程是具有一定独立功能的程序,是系统进行资源分配和调度的独立单位 线程进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位。真正在处理机上运行的是线程。 ...
  • linux进程线程之间通信方法和同步方法总结; 共享内存,消息队列,管道; 信号量,互斥锁,条件变量,读-写锁
  • 操作系统的主要任务是管理计算机的软件、硬件资源。现代操作系统的主要特点是多用户和多任务,也就是程序的并行执行,...而线程通信又和进程间的通信不同。由于进程的数据空间相对独立而线程是共享数据空间的,
  • Linux 进程与线程概念解析

    千次阅读 2017-06-18 21:58:36
    线程(thread)技术早在60年代就被提出,但真正应用多...现在,多线程技术已经被许多操作系统所支持,包括Windows/NT、Linux进程进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元;
  • windows和linux进程与线程通信

    千次阅读 2017-02-17 11:57:04
    http://www.yingzinanfei.com/2017/02/17/windowshelinuxjinchengjianyuxianchengjiantongxin/Linux进程通信:管道、信号、消息队列、共享内存、信号量、套接字(socket) Linux线程通信:互斥量(mutex),信号...
  • Windows和Linux进程与线程的区别

    千次阅读 2018-08-28 17:14:25
    也就是说windows对于进程线程的定义是经典OS课程中所教授的进程线程概念相一致的。 提供API,CreateThread()用于建立一个新的线程,传递线程函数的入口地址和调用参数给新建的线程,然后新线程就开始执行了。...
  • (3)线程执行过程中容易同步,而进程之间需要通信进行同步。 (4)线程共享进程数据的同时,拥有自己的堆栈。2、线程的一些优点: (1)由于线程用所属进程的一些资源,线程的划分尺度更小,并发性比
  • 本文主要介绍了 Linux系统中进程线程通信方式总结 。
  • Linux系统中的进程通信方式主要以下几种: 同一主机上的进程通信方式  * UNIX进程通信方式: 包括管道(PIPE), 有名管道(FIFO), 和信号(Signal)  * System V进程通信方式:包括信号量(Semaphore), 消息...
  • Linux进程/线程 通信方式总结

    千次阅读 2012-11-13 10:45:36
    linux系统中的进程通信方式主要以下几种: PIPE(FIFO) 消息队列 信号量(Semaphore) 共享存储 SOCKET 同一主机上的进程通信方式  * UNIX进程通信方式: 包括管道(PIPE), 有名...
  • 也就是说windows对于进程线程的定义是经典OS课程中所教授的进程线程概念相一致的。 提供API,CreateThread()用于建立一个新的线程,传递线程函数的入口地址和调用参数给新建的线程,然后新线程就开始执行了。...
  • 代码 任务书 课程设计报告都有 直接可以用
  • 课程目标 进程相关的基本概念 Linux进程的创建 Linux进程的管理和守护进程 Linux进程通信的方式 Linux中线程创建和退出 Linux中线程间的同步和互斥 本章内容 6.1 Linux进程概述 6.2 Linux进程控制相关API 6.3 ARM ...
  • Linux线程同步与进程通信

    千次阅读 2020-02-27 18:00:48
    线程同步与进程通信 线程同步 互斥量 临界资源:在一段时间内只允许一个任务(线程进程)访问资源。任务之间采用互斥的方式访问临界资源 互斥量:pthread_mutex_t mutex; 初始化、加锁、解锁、销毁 加锁:...
  • 首先,简要了解一下进程线程。对于操作系统而言,进程是核心之核心,整个现代操作系统的根本,就是以进程为单位在执行任务。系统的管理架构也是基于进程层面的。在按下电源键之后,计算机就开始了复杂的启动过程,...
  • Linux进程线程编程

    2012-04-20 18:27:53
    这个资料是我精心寻找的一些LINUX进程线程方面的资料,包括了LINUX进程线程编程,进程间通信等内容,是学习LINXU系统编程比较好的而且容易理解的一些编程资料
  • Linux进程线程的比较

    千次阅读 2014-10-17 15:26:46
    首先比较Linux进程线程的创建的区别,以此展开: 创建进程:(1)调用fork(),为子进程新建内核栈、pthread_info和task_struct,复制父进程的大部分的参数,采用写时复制(copy-on-write)辅助父进程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,564
精华内容 42,625
关键字:

linux进程与线程通信

linux 订阅