精华内容
下载资源
问答
  • 线程1 线程简介(1)线程的特点:(2)线程资源1)共享资源2)私有资源2 Linux线程库3 线程创建 - pthread_create4 线程回收 - pthread_join5 线程结束 - pthread_exit6 线程实例 1 线程简介 首先进程有如下特点: ...

    1 线程简介

    首先进程有如下特点:

    • 有独立的地址空间;
    • 每个进程创建task_struct;
    • 都参与内核调度,互不影响。
      缺点是,切换时系统开销大。
      下图是一个进程读取数据的流程在这里插入图片描述
      CPU先获取cache,读指令,访问数据,若cache中无数据,再从内存中加载一批数据。

    (1)线程的特点:

    • 是轻量级进程(LWP);
    • 同一进程中的线程共享相同的地址空间;
    • LInux不区分进程线程;
    • 进程独占一个空间,线程共享地址空间;
      根据线程的特点,多线程有以下优势
    • 大大提高了任务切换的效率;
    • 避免额外的tlb和cache刷新。

    (2)线程资源

    1)共享资源

    • 可执行指令;
    • 静态数据;(全局变量,字符串变量等);
    • 进程中打开的文件描述符;
    • 当前工作目录;
    • 用户ID;
    • 用户组ID。

    2)私有资源

    • 线程ID(TID);
    • PC(程序计数器)和相关寄存器(可执行独立代码);
    • 堆栈(局部变量);
    • 错误号(errno);
    • 优先级;
    • 执行状态和属性。

    2 Linux线程库

    pthread线程库提供了如下基本操作

    • 创建线程
    • 回收线程
    • 结束线程

    同步和互斥机制

    • 信号量
    • 互斥锁

    3 线程创建 - pthread_create

    #include <pthread.h>
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*routine)(void *), void *arg);

    • 成功返回0,失败返回错误码;
    • thread 线程对象;
    • attr 线程属性,NULL代表默认属性;
    • routine线程执行的函数;
    • arg 传递给routine的参数。

    4 线程回收 - pthread_join

    #include <pthread.h>
    int pthread_join (pthread_t thread, void **retval);

    • 成功返回0,失败返回错误码;
    • thread是指要回收的线程对象;
    • 调用线程阻塞直到thread结束;
    • *retval 一级指针传地址,接收线程thread的返回值。

    5 线程结束 - pthread_exit

    #include <pthread.h>
    void pthread_exit(void *retval);

    • 相当于return,即结束当前线程;
    • retval可被其他线程通过pthread_join获取;
    • 线程私有资源被释放;
    • 地址不能是线程战中创建的地址,线程结束后所有资源被释放,包括线程栈。

    6 线程实例

    char message[32] = "hello world"; //定义全局字符串数组,在静态存储区,
    									//可以被所有线程访问
    void *thread_func(void *arg);		//线程要执行函数
    
    int main(void){
    	pthread_t a_thread;				//线程对象变量
    	void *result					//接收返回值
    	
    	if( pthread_create(&a_thread, NULL, thread_func, NULL) != 0){
    		printf("fail to pthread_create");
    		exit(-1);
    	}
    
    	pthread_join(&a_thread, &result);
    	printf("result is %s\n", result);
    	printf("message is %s\n", message);
    	
    	return 0;
    }
    
    void thread_func(void *arg){
    	sleep(1);
    	strcpy(message, "marked by thread");
    	pthread_exit("thank you for waiting for me");
    }
    

    执行指令
    $ gcc -o test test.c -l pthread
    $./test
    结果:
    thank you for waiting for me
    masked by thread

    展开全文
  • 线程的特点 通常线程指的是共享相同地址空间的多个任务 使用多线程的好处 大大提高了任务切换的效率 避免了额外的TLB & cache的刷新 线程共享资源 线程私有资源 可执行的指令 线程

    线程的概念

    进程

    • 进程有独立的地址空间
    • Linux为每个进程创建task_struct
    • 每个进程都参与内核调度,互不影响

    线程

    • 进程在切换时系统开销大
    • 很多操作系统引入了轻量级进程LWP
    • 同一进程中的线程共享相同地址空间
    • Linux不区分进程,线程(均会创建task_struct)

    线程的特点

    • 通常线程指的是共享相同地址空间的多个任务
    • 使用多线程的好处
      • 大大提高了任务切换的效率
      • 避免了额外的TLB & cache的刷新
    线程共享资源 线程私有资源
    可执行的指令 线程ID(TID)
    静态数据 PC(程序计数器)和相关寄存器
    进程中打开的文件描述符 堆栈
    当前工作目录 错误号(errno)
    用户ID 优先级
    用户组ID 执行状态和属性

    线程操作

    LINUX线程库

    • pthread线程库
      • 创建线程
      • 回收线程
      • 结束线程
    • 同步和互斥机制
      • 信号量
      • 互斥锁

    线程创建

    #include<pthread.h>
    int pthread_create(pthread_t *thread,const pthread_attr_t * attr,void ( routine)(void *),void *arg);

    • 成功返回0,失败返回错误码
    • thread:线程对象
    • attr:线程属性,NULL表示默认属性
    • routine:线程执行的函数
    • arg:传递给routine的参数

    线程回收

    #include<pthread.h>
    int pthread_join(pthread_t thread,void **retval);

    • 成功返回0,失败返回错误码
    • 调用线程阻塞直到thread结束
    • thread:要回收的线程对象
    • *retval:接收线程thread的返回值

    线程结束

    #include<pthread.h>
    void pthread_exit(void *retval);

    • 结束当前线程
    • retval可被其他线程通过pthread_join获取
    • 线程私有资源被释放

    测试

    #include<stdio.h>
    #include<string.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<unistd.h>
    
    char message[32] = "Hello World";
    void *thread_func(void *arg);
    
    int main(void){
    	pthread_t a_thread;
    	void *result;
    	if(pthread_create(&a_thread,NULL,thread_func,NULL)!=0){
    		printf("fail to pthread_create\n");
    		exit(-1);
    	}
    	pthread_join(a_thread,&result);
    	printf("result is %s\n",(char *)result);
    	printf("message is %s\n",message);
    	return 0;
    }
    void *thread_func(void *arg){
    	sleep(1);
    	strcpy(message,"marked by thread");
    	pthread_exit("thank you for waiting for me");
    }
    
    

    同步和互斥机制

    线程间通信

    • 线程共享同一进程的地址空间
    • 优点:线程间通信很容易(通过全局变量交换数据)
    • 缺点:多个线程访问共享数据时需要同步或互斥机制

    线程通信 - 同步

    • 同步指的时多个任务按照约定的先后次序相互配合完成一件事情
    • 由信号量来决定线程是继续运行还是阻塞等待

    信号量

    • 信号量代表某一类资源,其值表示系统中该资源的数量
    • 信号量是一个受保护的变量,只能通过三种操作来访问
      • 初始化
      • P操作(申请资源)
      • V操作(释放资源)

    P/V操作

    • P(S)操作:
    if(信号量的值大于0){
    	申请资源的任务继续运行;
    	信号量的值减一;
    }
    else{
    	申请资源的任务阻塞;
    }
    
    • V(S)操作:
    信号量的值加一;
    if(有任务在等待资源){
    	唤醒等待的任务,让其继续运行;
    }
    

    Posix信号量

    • posix中定义了两类信号量:
      • 无名信号量(基于内存的信号量)
      • 有名信号量
    • pthread库常用的信号量操作函数如下:
      • int sem_init(sem_t *sem,int pshared,unsigned int value);
      • int sem_wait(sem_t *sem); //P操作
      • int sem_post(sem_t *sem);

    信号量初始化 - sem_init

    #include<semaphore.h>
    int sem_init(sem_t *sem,int pshared,unsigned int val);

    • 成功时返回0,失败时返回EOF
    • sem :指向要初始化的信号量对象
    • pshared 0-线程间 1-进程间
    • val 信号量初值

    信号量 - P/V操作

    #include<semaphore.h>
    int sem_wait(sem_t *sem); //P操作
    int sem_post(sem_t *sem); //V操作

    • 成功时返回0;失败时返回EOF
    • sem指向要操作的信号量对象

    测试

    两个线程同步读写缓冲区(生产者/消费者问题)

    #include<stdio.h>
    #include<string.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<semaphore.h>
    
    char buf[32];
    sem_t sem;
    void *function(void *arg);
    
    int main(){
    	pthread_t a_thread;
    	if(sem_init(&sem,0,0)<0){
    		perror("sem_init");
    		exit(-1);
    	}
    	if(pthread_create(&a_thread,NULL,function,NULL)!=0){
    		printf("fail to pthread_create\n");
    		exit(-1);
    	}
    
    	do{
    		fgets(buf,32,stdin);
    		sem_post(&sem);
    	}
    	while(strncmp(buf,"quit",4)!=0);
    
    	return 0;
    }
    
    void *function(void *arg){
    	while(1){
    		sem_wait(&sem);
    		printf("you enter %lu characters\n",strlen(buf));
    	}
    }
    

    1查看线程

    2
    改进读入超出缓冲区覆盖问题

    #include<stdio.h>
    #include<string.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<semaphore.h>
    
    char buf[32];
    sem_t sem;
    void *function(void *arg);
    
    int main(){
    	pthread_t a_thread;
    	if(sem_init(&sem,0,0)<0){
    		perror("sem_init");
    		exit(-1);
    	}
    	if(pthread_create(&a_thread,NULL,function,NULL)!=0){
    		printf("fail to pthread_create\n");
    		exit(-1);
    	}
    
    	do{
    		fgets(buf,32,stdin);
    		sem_post(&sem);
    	}
    	while(strncmp(buf,"quit",4)!=0);
    
    	return 0;
    }
    
    void *function(void *arg){
    	while(1){
    		sem_wait(&sem);
    		printf("you enter %lu characters\n",strlen(buf));
    	}
    }
    

    3

    临界资源

    线程通信 - 互斥

    • 临界资源
      • 一次只允许一个任务(进程,线程)访问的共享资源
    • 临界区
      • 访问临界区的代码
    • 互斥机制
      • mutex互斥锁
      • 任务访问临界资源前申请锁,访问完后释放锁

    互斥锁初始化 - pthread_mutex_init

    #include<pthread.h>
    int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);

    • 成功时返回0,失败时返回错误码
    • mutex:指向要初始化的互斥锁对象
    • attr:互斥锁属性,NULL表示缺省属性

    申请锁 - pthread_mutex_lock

    #include<pthread.h>
    int pthread_mutex_lock(pthread_mutex_t *mutex);

    • 成功时返回0,失败时返回错误码
    • mutex:指向要初始化的互斥锁对象
    • 如果无法获得锁,任务阻塞

    释放锁 - pthread_mutex_unlock

    #include<pthread.h>
    int pthread_mutex_unlock(pthread_mutex_t *mutex);

    • 成功时返回0,失败时返回错误码
    • mutex 指向要初始化的互斥锁对象
    • 执行完临界区要及时释放锁

    测试

    #include<stdio.h>
    #include<string.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<semaphore.h>
    unsigned int count,value1,value2;
    pthread_mutex_t lock;
    
    void *function(void *arg);
    int main(void){
    	pthread_t a_thread;
    	if(pthread_mutex_init(&lock,NULL)!=0){
    		printf("fail to prhread_mutex_init\n");
    		exit(-1);
    	}
    	if(pthread_create(&a_thread,NULL,function,NULL)!=0){
    		printf("fail to pthread_creat");
    		exit(-1);
    	}
    	while(1){
    		count++;
    		#ifdef _LOCK_
    			pthread_mutex_lock(&lock);
    		#endif
    			value1 = count;
    			value2 = count;
    		#ifdef _LOCK_
    			pthread_mutex_unlock(&lock);
    		#endif
    	}
    	return 0;
    }
    
    void *function(void *arg){
    		while(1){
    			#ifdef _LOCK_
    				pthread_mutex_lock(&lock);
    			#endif
    			if(value1 != value2){
    				printf("value1 = %u,value2 = %u\n",value1,value2);
    				usleep(100000);
    			}
    			#ifdef _LOCK_
    				pthread_mutex_unlock(&lock);
    			#endif
    		}
    		return NULL;
    }
    
    • 不使用互斥锁
    • gcc -o test test.c -lphread
    • 使用互斥锁
    • gcc -o test test.c -lphread -D_LOCK_//-D选项可以添加宏定义
      4
    展开全文
  • 《实战Java高并发程序设计》读书笔记六 第六章 Java 8 与并发 1、函数式编程 函数作为一等公民: 将函数作为参数传递给另外一个函数这是函数式编程特性之一。 函数可以作为另外一个函数...

    《实战Java高并发程序设计》读书笔记六

    第六章 Java 8 与并发

    1、函数式编程

    函数作为一等公民:

    • 将函数作为参数传递给另外一个函数这是函数式编程的特性之一。
    • 函数可以作为另外一个函数的返回值,也是函数式编程的重要特点。

    无副作用:

    • 函数的副作用是指在函数调用过程中除了给出了返回值以外还修改了其他函数的外部状态。

    申明式:

    • 函数式编程是申明式编程,不再需要提供明确的指令操作,所有细节指令将会更好的被程序库所封装,只要提出要求申明用意即可。

    不变的对象:

    • 在函数式编程中,几乎所有传递的对象都不会被轻易修改。

    易于并行:

    • 由于对象都处于不变的状态,因此函数式编程更加易于并行。

    更少的代码:

    • 通常情况下,函数式编程更加简明扼要,精简的代码更易于维护。

    2、函数式编程基础

    FunctionalInterface注释:

    • Java 8 提出了函数式接口的概念。函数式接口就是只定义了单一抽象方法的接口,如果符合这个定义即使没有使用注释编译器也会把他看做函数式接口。
    • 函数式接口是只能有一个抽象方法,而不是只能有一个方法。其次任何被Object实现的方法都不能视为抽象方法。
    • 函数式接口可以由方法引用或者lambda表达式进行构造。

    接口默认方法:

    • Java 8之前接口只能包含抽象方法,但在Java 8 后接口可以包含若干个使用default修饰的实例方法。
    • 接口默认方法会带来多继承的问题,继承的接口有两个一样的方法时需要重写这个方法指定调用那个接口的方法。

    lambda表达式:

    • lambda是函数式编程的核心,lambda表达式即匿名函数,是一段没有函数名的函数体,可以作为参数直接传递给相关的调用者

    方法引用:

    • 方法引用是Java 8 中提出的用来简化lambda表达式的手段,它通过类名和方法名来定位到一个静态方法或者实例方法。
    • 静态方法引用:ClassName::methodName
    • 类型上的实例方法引用:ClassName::methodName
    • 构造方法的引用:ClassName::new
    • 实例上的实例方法引用:instanceReference::methodName
    • 超类上的实例方法引用:super::methodName
    • 数组构造方法引用:TypeName[]::new
      package com.ecut.lambda;
      
      import java.io.Serializable;
      
      public class User implements Serializable {
      
          private int id;
      
          private String name;
      
          public User(int id , String name){
              this.id = id ;
              this.name = name ;
          }
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      }
      package com.ecut.lambda;
      
      import java.util.ArrayList;
      import java.util.List;
      
      public class LambdaTest {
      
          @FunctionalInterface
          interface UserFactory<U extends User> {
              U creat(int id, String name);
          }
      
          static UserFactory<User> userFactory = User::new;
      
          public static void main(String[] args) {
              List<User> users = new ArrayList<>();
              for (int i = 0; i < 10; i++) {
                  users.add(userFactory.creat(i, "user" + Integer.toString(i)));
              }
              users.stream().map(User::getName).forEach(System.out::println);
          }
      }

      UserFactory作为User的工厂类是一个函数式接口。当使用User::new创建接口实例时,系统会UserFactory.create()的函数签名来选择合适的User构造函数签名来选择合适的User构造函数。在创建UserFactory实例后,对UserFactory.create()的调用都会委托给User的实际构造函数进行,从而创建User对象实例。

    3、走入函数式编程

    函数式编程测试案例:

    package com.ecut.lambda;
    
    import java.util.Arrays;
    import java.util.function.IntConsumer;
    
    public class HelloLambaTest {
        static int[] arr = {1, 2, 3, 4, 5};
    
        public static void main(String[] args) {
            //普通输出
            for (int i : arr) {
                System.out.println(i);
            }
            /*使用Java 8中的流 Arrays.stream返回了一个流对象。类似于集合或者数组。foreach接受了一个IntConsumer接口的实现用于对流内部
            对象的处理*/
            Arrays.stream(arr).forEach(new IntConsumer() {
                @Override
                public void accept(int value) {
                    System.out.println(value);
                }
            });
    
            //省略foreach参数
            Arrays.stream(arr).forEach((final int value) -> {
                System.out.println(value);
            });
    
            //省略参数类型
            Arrays.stream(arr).forEach((value) -> {
                System.out.println(value);
            });
    
            //使用lambda表达式,省略括号
            Arrays.stream(arr).forEach(value -> System.out.println(value));
    
            //使用方法引用
            Arrays.stream(arr).forEach(System.out::println);
    
        }
    }

    lambda不仅可以简化匿名类的编写与接口默认方法相结合还可以使用流畅的流式API对各种组件进行更自由的装配。

    //流式API
    IntConsumer out = System.out::println;
    IntConsumer err = System.err::println;
    Arrays.stream(arr).forEach(out.andThen(err));

    4、并行流和并行排序

    并行流过滤数据:

    package com.ecut.lambda;
    
    import java.util.stream.IntStream;
    
    public class ParallelFilterTest {
    
        public static boolean isPrime(int number){
            int tmp = number ;
            if(tmp < 2){
                return false;
            }
            for (int i = 2 ; Math.sqrt(tmp) >= i ; i++){
                if(tmp % i == 0) {
                    return  false;
                }
            }
            return true;
        }
    
        public static void main(String[] args) {
            long count = IntStream.range(1,1000000).parallel().filter(ParallelFilterTest::isPrime).count();
            System.out.println(count);
        }
    }

    从集合得到并行流:

    package com.ecut.lambda;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ParallelStreamTest {
        public static void main(String[] args) {
            List<User> users = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                users.add(new User(i, "user" + i));
            }
            double avg = users.parallelStream().mapToInt(User::getId).average().getAsDouble();
            System.out.println(avg);
        }
    }

    并行排序:

    package com.ecut.lambda;
    
    import java.util.Arrays;
    
    public class ParallelSortTest {
        public static void main(String[] args) {
            int[] arr = {8, 5 ,7,2,9,1};
            Arrays.parallelSort(arr);
            for(int i = 0 ; i < arr.length ; i++){
                System.out.println(arr[i]);
            }
        }
    }

    5、增强的Future CompletableFuture

    可以手动设置CompletableFuture的完成状态:

    package com.ecut.completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    
    public class CompleteTest {
        public static class AskThread implements Runnable {
    
            private CompletableFuture<Integer> completableFuture = null;
    
            public AskThread(CompletableFuture<Integer> completableFuture) {
                this.completableFuture = completableFuture;
            }
    
            @Override
            public void run() {
                try {
                    // CompletableFuture中没有数据,处于未完成状态
                    System.out.println(completableFuture.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            CompletableFuture<Integer> completableFuture = new  CompletableFuture<>();
            //没有数据,请求线程一直等待
            new Thread(new AskThread(completableFuture)).start();
            //手动设置完成结果
            completableFuture.complete(1);
        }
    }

    异步执行任务:

    package com.ecut.completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    
    public class AsyncTest {
    
        private static Integer calc(Integer para){
            try {
                //模拟长时间的计算过程
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return para*para;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->calc(60));
            System.out.println(completableFuture.get());
        }
    }

    流式调用:

    CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(()->calc(60)).thenApply((i) -> Integer.toString(i)).thenAccept(System.out::println);

    异常处理:

    package com.ecut.completablefuture;
    
    import java.util.concurrent.CompletableFuture;
    
    public class ExceptionTest {
        private  static  Integer Div(Integer para){
            return para / 0 ;
        }
    
        public static void main(String[] args) {
            CompletableFuture<Integer> completeFuture = CompletableFuture.supplyAsync(()->Div(1)).exceptionally(ex ->{
                System.out.println(ex.toString());
                return 0;
            });
        }
    }

     6、StampedLock

    源码地址:

    https://github.com/SaberZheng/concurrent-test

    转载请于明显处标明出处:

    https://www.cnblogs.com/AmyZheng/p/10486212.html

    posted @ 2019-03-07 19:13 AmyZheng 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 文章目录 ... 在了解进程之前我们需要了解什么是程序程序就是存放在磁盘上指令和数据有序集合(文件),程序是静态程序编译好以后指令、数据等就不能再改变)。 进程与程序是密切相关,...
    
    
    

     

    进程的概念

           在了解进程之前我们需要了解什么是程序,程序就是存放在磁盘上的指令和数据的有序集合(文件),程序是静态的(程序编译好以后指令、数据等就不能再改变)。
           进程与程序是密切相关的,进程是操作系统为了执行一个程序分配资源的总称、是程序的一次执行过程,进程相当于程序来说是动态的,包括创建、调度、执行和消亡。当系统执行一个程序时,至少创建了一个进程

    进程内容

    在这里插入图片描述
           进程主要包括代码(正文)、用户程序、系统数据。系统数据有助于操作系统管理进程。系统数据段主要包括进程控制块(PCB Process Control Block)、CPU寄存器值、堆栈。

    系统数据段 作用
    进程控制块(pcb) ① 进程标识PID ② 进程用户 ③ 进程状态、优先级 ④文件描述符表
    寄存器 程序计数器PC(program counter)该寄存器保存了程序下一个指令的地址
    堆栈 C语言局部变量、函数的参数、返回值都是在栈上创建的

    进程类型

    • 交互进程:在Shell下启动。以在前台运行,也可以在后台运行。(后台运行给指令后加一个‘&’)
    • 批处理进程:与在终端无关,被提交到一个作业队列中以便执行
    • 守护进程:和终端没有关系,一直在后台运行

    进程的状态

    • 运行态:进程正在运行,或者准备运行
    • 等待态:进程在等待一个事件的发生某种系统资源(分为可中断和不可中断)
    • 停止态:进程被终止,收到信号后可继续运行
    • 死亡态:已终止的程序,但是pcb没有被释放
    • 进程状态图:

    Linux下进程的相关命令

    查看进程相关信息

    终端命令 显示结果
    ps -ef 进程所有者、进程号、父进程号、进程执行时间、程序对应名称
    ps aux 相对于ps -ef还能够显示进程的当前状态(运行态、停止态、前台进程等)
    top 可以查看进程动态信息(每隔3秒钟统计系统信息)能显示系统最消耗CPU资源的进程
    /proc目录查看 进入该目录下可以查看进程的详细信息

    注意使用ps命令都可以配合管道命令进行筛选相关进程信息

    修改进程优先级

    命令 作用
    nice 按用户指定优先级运行进程
    renice 改变正在运行进程的优先级

    示例:

    <span style="color:#000000"><code class="language-bash"><span style="color:#dd4a68">nice</span> -n 2 ./test<span style="color:#708090">#将test进程的nice值设置为2</span>
    
    <span style="color:#dd4a68">renice</span> -n 2 29070<span style="color:#708090">#将进程号为29070的nice值设置为2</span>
    </code></span>
    • 1
    • 2
    • 3

    注意进程的nice值默认是0,范围为- 20~20,nice值越小则优先级越高。普通用户设置的nice值只能为0 ~ 20,且只能增加nice值

    前后台进程切换

    命令 作用
    jobs 查看后台进程(作业)
    bg 将挂起的进程在后台运行
    fg 把后台运行的进程放到前台运行

    进程相关函数

    创建进程——fork

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><unistd.h></span></span>
    pid_t <span style="color:#dd4a68">fork</span><span style="color:#999999">(</span><span style="color:#0077aa">void</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//pid_t 等价与有符号整型</span>
    </code></span>
    • 1
    • 2
    • 创建新的进程,失败返回-1
    • 创建成功时,父进程返回子进程的进程号,子进程返回0
    • 通过fork()的返回值来区分父子进程

    示例:

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span><span style="color:#50a14f"><stdio.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span><span style="color:#50a14f"><unistd.h></span></span>
    
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">main</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
    <span style="color:#999999">{</span>
        pid_t pid<span style="color:#999999">;</span>
        <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#999999">(</span>pid<span style="color:#a67f59">=</span><span style="color:#dd4a68">fork</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"fork"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//创建失败,打印错误信息</span>
    	<span style="color:#0077aa">return</span> <span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
        <span style="color:#0077aa">else</span> <span style="color:#0077aa">if</span><span style="color:#999999">(</span>pid<span style="color:#a67f59">==</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">printf</span><span style="color:#999999">(</span><span style="color:#50a14f">"child prosess:my pid is %d\n"</span><span style="color:#999999">,</span><span style="color:#dd4a68">getpid</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//创建子进程,返回子进程的pid号</span>
        <span style="color:#999999">}</span>
        <span style="color:#0077aa">else</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">printf</span><span style="color:#999999">(</span><span style="color:#50a14f">"parent process:my pid is %d\n"</span><span style="color:#999999">,</span><span style="color:#dd4a68">getpid</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//打印父进程的进程号</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    父子进程

    • 子进程继承了父进程的内容(几乎赋值了父进程的全部内容,但是pid、ppid不同)
    • 父子进程有独立的地址空间,互不影响
    • 若父进程先结束
      • 子进程成为孤儿进程,被init进程收养
      • 子进程变成后台进程
    • 若子进程先结束
      • 父进程如果没有及时回收,子进程变成僵尸进程

    注意:
           1. 子进程是从fork函数的下一条语句开始执行,并没有执行fork
           2. 内核先调用父进程就先执行父进程,先调用子进程就先执行子进程
           3. 父进程可以多次调用fork,子进程也可以调用fork创建孙进程(注意进程的回收)

    结束进程——exit/_exit/return

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdlib.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><unistd.h></span></span>
    <span style="color:#0077aa">void</span> <span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#0077aa">int</span> status<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//用stdlib.h头文件</span>
    <span style="color:#0077aa">void</span> <span style="color:#dd4a68">_exit</span><span style="color:#999999">(</span><span style="color:#0077aa">int</span> status<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//用unistd.h头文件</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 结束当前的进程并将status返回
    • exit结束后会刷新流的缓冲区
      示例:
    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdio.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdlib.h></span></span>
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">main</span><span style="color:#999999">(</span><span style="color:#0077aa">void</span><span style="color:#999999">)</span>
    <span style="color:#999999">{</span>
    	<span style="color:#dd4a68">printf</span><span style="color:#999999">(</span><span style="color:#50a14f">"this process will exit"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//没有换行符只能写到标准输出流的缓冲区,不会在终端显示</span>
    	<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//结束进程,刷新缓冲区的流,因此上条语句会显示在终端上</span>
    	<span style="color:#dd4a68">printf</span><span style="color:#999999">(</span><span style="color:#50a14f">"never be discovered"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//不会被打印	</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    exec函数族

    作用

    • 进程调用exec函数族执行某个程序
    • 进程当前内容被指定程序替换
    • 实现父子进程执行不同程序
      • 父进程创建子进程
      • 父进程调用exec函数族
      • 父进程不受影响
    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><unistd.h></span></span>
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">execl</span><span style="color:#999999">(</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>path<span style="color:#999999">,</span><span style="color:#0077aa">const</span> <span style="color:#a67f59">*</span>arg<span style="color:#999999">,</span><span style="color:#999999">.</span><span style="color:#999999">.</span><span style="color:#999999">.</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//arg...传递给执行的程序的参数列表</span>
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">execlp</span><span style="color:#999999">(</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>file<span style="color:#999999">,</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>arg<span style="color:#999999">,</span><span style="color:#999999">.</span><span style="color:#999999">.</span><span style="color:#999999">.</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//arg...传递给执行的程序的参数列表</span>
    
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">execv</span><span style="color:#999999">(</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>path<span style="color:#999999">,</span><span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span><span style="color:#0077aa">const</span> argv<span style="color:#999999">[</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//arg...封装成指针数组的形式</span>
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">execvp</span><span style="color:#999999">(</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span><span style="color:#a67f59">*</span>file<span style="color:#999999">,</span><span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span><span style="color:#0077aa">const</span> argv<span style="color:#999999">[</span><span style="color:#999999">]</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//arg...封装成指针数组的形式 </span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 成功时返回指定程序;失败时返回EOF
    • path执行的程序名称,包含路径
    • file执行程序的名称,在PATH中查找

    示例:

           执行ls命令,显示/etc目录下所有文件的详细信息

    <span style="color:#000000"><code class="language-c">方式<span style="color:#986801">1</span>:execl
    <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">execl</span><span style="color:#999999">(</span><span style="color:#50a14f">"/bin/ls"</span><span style="color:#999999">,</span><span style="color:#50a14f">"ls"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-a"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-l"</span><span style="color:#999999">,</span><span style="color:#50a14f">"/etc"</span><span style="color:#999999">,</span><span style="color:#986801">NULL</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">{</span><span style="color:#708090">//一定要以NULL结尾,并判断函数是否执行成功</span>
    	<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"execl"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>	
    
    方式<span style="color:#986801">2</span>:execlp
    <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">execl</span><span style="color:#999999">(</span><span style="color:#50a14f">"ls"</span><span style="color:#999999">,</span><span style="color:#50a14f">"ls"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-a"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-l"</span><span style="color:#999999">,</span><span style="color:#50a14f">"/etc"</span><span style="color:#999999">,</span><span style="color:#986801">NULL</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">{</span><span style="color:#708090">//会自动在PATH路劲搜索</span>
    	<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"execl"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>	
    方式<span style="color:#986801">3</span>:execv
    <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>arg<span style="color:#999999">[</span><span style="color:#999999">]</span><span style="color:#a67f59">=</span><span style="color:#999999">{</span><span style="color:#50a14f">"ls"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-a"</span><span style="color:#999999">,</span><span style="color:#50a14f">"-l"</span><span style="color:#999999">,</span><span style="color:#50a14f">"/etc"</span><span style="color:#999999">,</span><span style="color:#986801">NULL</span><span style="color:#999999">}</span><span style="color:#999999">;</span><span style="color:#708090">//将要传递的参数放在数组中</span>
    <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">execv</span><span style="color:#999999">(</span><span style="color:#50a14f">"/bin/ls"</span><span style="color:#999999">,</span>arg<span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"execv"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    方式<span style="color:#986801">3</span><span style="color:#999999">:</span>execvp
    <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">execvp</span><span style="color:#999999">(</span><span style="color:#50a14f">"ls"</span><span style="color:#999999">,</span>arg<span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"execvp"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//会自动在PATH路径中搜索</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    system函数

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdlib.h></span></span>
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">system</span><span style="color:#999999">(</span><span style="color:#0077aa">const</span> <span style="color:#0077aa">char</span> <span style="color:#a67f59">*</span>command<span style="color:#999999">)</span>
    </code></span>
    • 1
    • 2
    • 成功时返回command的返回值;失败时返回EOF(自动创建一个子进程,子进程执行命令)
    • 当前进程(父进程)等待command执行结束后才继续执行。

    进程回收——wait/waitpid

    • 子进程结束时由父进程回收
    • 孤儿进程由init进程回收
    • 若孤儿进程没有回收会出现僵尸进程

    回收函数——wait:

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><unistd.h></span></span>
    pid_t <span style="color:#dd4a68">wait</span><span style="color:#999999">(</span><span style="color:#0077aa">int</span> <span style="color:#a67f59">*</span>status<span style="color:#999999">)</span><span style="color:#999999">;</span>
    </code></span>
    • 1
    • 2
    • 成功时返回回收子进程的进程号;失败时返回EOF
    • 若子进程没有结束,父进程一直阻塞
    • 若有多个子进程,那个进程先结束就先回收
    • status指定保存子进程返回值和结束方式的地址
    • status为NULL表示直接释放子进程PCB,不接收返回值

    示例:

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span><span style="color:#50a14f"><stdio.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span><span style="color:#50a14f"><unistd.h></span></span>
    
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">main</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
    <span style="color:#999999">{</span>
        <span style="color:#0077aa">int</span> status<span style="color:#999999">;</span><span style="color:#708090">//接收返回值以及返回方式</span>
        pid_t pid<span style="color:#999999">;</span><span style="color:#708090">//接收fork的返回值</span>
        <span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#999999">(</span>pid<span style="color:#a67f59">=</span><span style="color:#dd4a68">fork</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
            <span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"fork"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
            <span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
        <span style="color:#0077aa">else</span> <span style="color:#0077aa">if</span><span style="color:#999999">(</span>pid<span style="color:#a67f59">==</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
            <span style="color:#dd4a68">sleep</span><span style="color:#999999">(</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//如果是子进程睡眠一秒</span>
            <span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#986801">2</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//退出子进程</span>
        <span style="color:#999999">}</span>
        <span style="color:#0077aa">else</span><span style="color:#999999">{</span>
            <span style="color:#dd4a68">wait</span><span style="color:#999999">(</span><span style="color:#a67f59">&</span>status<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//等待子进程结束</span>
            <span style="color:#dd4a68">printf</span><span style="color:#999999">(</span><span style="color:#50a14f">"%x\n"</span><span style="color:#999999">,</span>status<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//打印输出结果</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 子进程通过exit/_exit/return返回某个值(0~255)
    • 父进程通过调用wait(&status)回收
    宏标识符 作用
    WIFEXITED(status) 判断子进程是否正常结束
    WEXITSTATUS(status) 获得子进程的返回值
    WIFSIGNALED(status) 判断子进程是否被信号结束
    WTERMSIG(status) 获取结束子进程的信号类型

    回收函数——wait_pid:

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span><span style="color:#50a14f"><unistd.h></span></span>
    pid_t <span style="color:#dd4a68">waitpid</span><span style="color:#999999">(</span>pid_t pid<span style="color:#999999">,</span><span style="color:#0077aa">int</span> status<span style="color:#999999">,</span><span style="color:#0077aa">int</span> option<span style="color:#999999">)</span><span style="color:#999999">;</span>
    </code></span>
    • 1
    • 2
    • 成功时返回回收子进程的pid或0;失败(如:没有子线程)返回EOF
    • pid可用于指定回收那个子进程或任意子进程
    • status指定用于保存子进程的返回值和结束方式的地址
    • option指定回收方式,0(阻塞的方式,等待子进程结束)或WNOHANG(非阻塞)

    示例:

    <span style="color:#000000"><code class="language-c"><span style="color:#dd4a68">waitpid</span><span style="color:#999999">(</span>pid<span style="color:#999999">,</span><span style="color:#a67f59">&</span>status<span style="color:#999999">,</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//指定进程的进程号,阻塞方式</span>
    <span style="color:#dd4a68">waitpid</span><span style="color:#999999">(</span>pid<span style="color:#999999">,</span><span style="color:#a67f59">&</span>status<span style="color:#999999">,</span>WNOHABG<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//子进程结束返回子进程的进程号,没有结束返回0</span>
    <span style="color:#dd4a68">waitpid</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">,</span><span style="color:#a67f59">&</span>status<span style="color:#999999">,</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//-1表示回收任意一个子进程,等价于wait</span>
    <span style="color:#dd4a68">waitpid</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">,</span><span style="color:#a67f59">&</span>status<span style="color:#999999">,</span>WNOHANG<span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//非阻塞的方式回收任意进程</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4

    守护进程

           守护进程(Daemon)是Linux三种类型之一,通常在系统启动时运行,系统结束时关闭,Linux系统中大量使用,很多服务程序就是以守护进程形式运行。
           Linux以会话(session)、进程组的方式管理进程,每个进程就属于一个进程组。而会话是一个或者多个进程组的集合。通常用户打开一个终端时,系统会创建一个临时会话,所有通过该终端运行的进程都属于这个会话。终端关闭时,所有进程会被结束。那么我们要使得守护进程与终端无关,当终端关闭的时候守护进程依旧可以运行。

    守护进程特点

    • 始终在后台运行
    • 独立于任何终端
    • 周期性的执行某种任务或等待处理特定事件

    守护进程的创建

    1. 创建子进程,父进程退出

    <span style="color:#000000"><code class="language-c"><span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">fork</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#a67f59">></span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 子进程变成孤儿进程,被init进程收养
    • 子进程在后台运行,但是依旧和终端相关联

    2. 子进程创建新会话

    <span style="color:#000000"><code class="language-c"><span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">setsid</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#708090">//通过setsid创建一个新的会话</span>
    <span style="color:#999999">{</span>
    	<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 子进程成为新的会话组长
    • 子进程脱离原先的终端

    3. 更改当前工作目录

    <span style="color:#000000"><code class="language-c"><span style="color:#dd4a68">chdir</span><span style="color:#999999">(</span><span style="color:#50a14f">"/"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#dd4a68">chdir</span><span style="color:#999999">(</span><span style="color:#50a14f">"/tmp"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//所有用户可读可写可执行</span>
    </code></span>
    • 1
    • 2
    • 守护进程一直在后台运行,其工作目录不能被卸载
    • 重新设定当前工作目录cwd

    4. 重设文件权限掩码

    <span style="color:#000000"><code class="language-c"><span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">umask</span><span style="color:#999999">(</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">{</span>
    	<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 文件权限掩码设置为0
    • 只影响当前进程

    5. 关闭打开的文件描述符

    <span style="color:#000000"><code class="language-c"><span style="color:#0077aa">int</span> i<span style="color:#999999">;</span>
    <span style="color:#0077aa">for</span><span style="color:#999999">(</span>i<span style="color:#a67f59">=</span><span style="color:#986801">0</span><span style="color:#999999">;</span>i<span style="color:#a67f59"><</span><span style="color:#dd4a68">getdtablesize</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>i<span style="color:#a67f59">++</span><span style="color:#999999">)</span><span style="color:#708090">//文件描述符最小就是0。getdtablesize()返回当前进程打开最大文件数</span>
    <span style="color:#999999">{</span>
    	<span style="color:#dd4a68">close</span><span style="color:#999999">(</span>i<span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    </code></span>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 关闭所有从父进程继承的打开文件
    • 已脱离终端,stdin/stdout/stderr无法再使用

    示例:
           创建守护进程,没隔1秒将系统时间写入文件time.log

    <span style="color:#000000"><code class="language-c"><span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdio.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><string.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><stdlib.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><strings.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><unistd.h></span></span>
    <span style="color:#986801">#<span style="color:#0077aa">include</span> <span style="color:#50a14f"><time.h></span></span>
    
    <span style="color:#0077aa">int</span> <span style="color:#dd4a68">main</span><span style="color:#999999">(</span><span style="color:#999999">)</span>
    <span style="color:#999999">{</span>
    	pid_t pid<span style="color:#999999">;</span>
    	FILE <span style="color:#a67f59">*</span>fp<span style="color:#999999">;</span>
    	time_t t<span style="color:#999999">;</span>
    	<span style="color:#0077aa">int</span> i<span style="color:#999999">;</span>
    
    	<span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#999999">(</span>pid <span style="color:#a67f59">=</span> <span style="color:#dd4a68">fork</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span> <span style="color:#986801">0</span><span style="color:#999999">)</span>
    	<span style="color:#999999">{</span>
    		<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"fork"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    		<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    	<span style="color:#999999">}</span>
    	<span style="color:#0077aa">if</span><span style="color:#999999">(</span>pid <span style="color:#a67f59">></span> <span style="color:#986801">0</span><span style="color:#999999">)</span>
    	<span style="color:#999999">{</span>
    		<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    	<span style="color:#999999">}</span>
    	<span style="color:#0077aa">else</span> <span style="color:#0077aa">if</span><span style="color:#999999">(</span>pid <span style="color:#a67f59">==</span> <span style="color:#986801">0</span><span style="color:#999999">)</span>
    	<span style="color:#999999">{</span>
    		<span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">setsid</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#a67f59"><</span> <span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#708090">//创建一个新的会话</span>
    		<span style="color:#999999">{</span>
    			<span style="color:#dd4a68">perror</span><span style="color:#999999">(</span><span style="color:#50a14f">"setsod"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    			<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    		<span style="color:#999999">}</span>
    		<span style="color:#0077aa">else</span>
    		<span style="color:#999999">{</span>
    			<span style="color:#dd4a68">chdir</span><span style="color:#999999">(</span><span style="color:#50a14f">"/tmp"</span><span style="color:#999999">)</span><span style="color:#999999">;</span><span style="color:#708090">//tmp目录可读可写可执行</span>
    			<span style="color:#0077aa">if</span><span style="color:#999999">(</span><span style="color:#dd4a68">umask</span><span style="color:#999999">(</span><span style="color:#986801">0</span><span style="color:#999999">)</span> <span style="color:#a67f59"><</span> <span style="color:#986801">0</span><span style="color:#999999">)</span><span style="color:#708090">//重设文件权限掩码</span>
    			<span style="color:#999999">{</span>
    				<span style="color:#dd4a68">exit</span><span style="color:#999999">(</span><span style="color:#a67f59">-</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    			<span style="color:#999999">}</span>
    			<span style="color:#0077aa">else</span>
    			<span style="color:#999999">{</span>
    				<span style="color:#0077aa">for</span><span style="color:#999999">(</span>i<span style="color:#a67f59">=</span><span style="color:#986801">0</span><span style="color:#999999">;</span>i<span style="color:#a67f59"><</span><span style="color:#dd4a68">getdtablesize</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>i<span style="color:#a67f59">++</span><span style="color:#999999">)</span>
    				<span style="color:#999999">{</span>
    					<span style="color:#dd4a68">close</span><span style="color:#999999">(</span>i<span style="color:#999999">)</span><span style="color:#999999">;</span>
    				<span style="color:#999999">}</span>
    			<span style="color:#999999">}</span>
    			<span style="color:#0077aa">while</span><span style="color:#999999">(</span><span style="color:#986801">1</span><span style="color:#999999">)</span>
    			<span style="color:#999999">{</span>
    				fp <span style="color:#a67f59">=</span> <span style="color:#dd4a68">fopen</span><span style="color:#999999">(</span><span style="color:#50a14f">"time.log"</span><span style="color:#999999">,</span><span style="color:#50a14f">"a+"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    				<span style="color:#dd4a68">time</span><span style="color:#999999">(</span><span style="color:#a67f59">&</span>t<span style="color:#999999">)</span><span style="color:#999999">;</span>
    				<span style="color:#dd4a68">fprintf</span><span style="color:#999999">(</span>fp<span style="color:#999999">,</span><span style="color:#50a14f">"%s"</span><span style="color:#999999">,</span><span style="color:#dd4a68">ctime</span><span style="color:#999999">(</span><span style="color:#a67f59">&</span>t<span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    				<span style="color:#dd4a68">fflush</span><span style="color:#999999">(</span>fp<span style="color:#999999">)</span><span style="color:#999999">;</span>
    				<span style="color:#dd4a68">sleep</span><span style="color:#999999">(</span><span style="color:#986801">1</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    			<span style="color:#999999">}</span>
    		<span style="color:#999999">}</span>
    	<span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
    </code></span>
    •  
    展开全文
  • 程序就是存放在磁盘上指令和数据有序集合(文件),程序时静态。 指令和数据有何特点? 1.指令和数据都是按地址寻访,他们存放在存储器中。 2.指令和数据都采用二进制表示。 3.指令由操作码和地址码组成,操作...
  • 文章目录1,有名管道的特点2,有名管道的创建mkfifo()3,有名管道读写---示例 1,有名管道的特点 对应管道文件,可用于任意进程之间进行通信:有名管道创建好之后,在系统中有实际的文件和有名管道对应,...
  • 提高锁性能 1)减小持有锁时间 ...类似读写锁分离概念,依据应用程序的功能特点,对独占锁进行分离 LinkedBlockingQueue中,take()和put()对应定义了takeLock和putLock,进行分离 5)锁粗化...
  • 一个Actor内部消息处理函数可以拥有多个不同状态,在特点的状态下,可以对同一消息进行不同处理,状态之间也可以任意切换。 现在模拟一个婴儿Baby,假设婴儿会拥有两种不同状态,开心或者生气。当带他玩...
  • 函数可以作为另外一个函数返回值,也是函数式编程重要特点。 2)无副作用 函数副作用指是函数在调用过程中,除了给出了返回值外,还修改了函数外部状态。比如,函数在调用过程中,修改了一个全局状态。...
  • 文章目录线程概念(了解)线程特点(了解)线程创建(熟练)创建pthread_create删除pthread_join结束pthread_exit线程 e.g.线程通信同步-POSIX信号量互斥互斥锁初始化-pthread_mutex_init释放锁-pthread_mutex_...
  • 1)原子性 原子性是指一个操作是不可中断。即使是在多个线程一起执行时候,一个操作一旦开始,就不会被其他线程干扰。...这就是原子性一个特点,不可被中断。 但是如果不使用int而使用long
  • 文章目录进程间通信无名管道(pipe)pipe特点pipe创建读pipe写pipe验证管道断裂 进程间通信 早期unix进程间通信 无名管道(pipe) 有名管道(fifo) 信号(signal) system V IPC 共享内存(share momeory) 消息队列...
  • 文章目录进程回收wait进程返回值和结束方式waitpid守护进程守护进程特点会话、控制终端守护进程创建(一)守护进程创建(二)守护进程创建(三)守护进程创建(四)守护进程创建(五)example 进程回收 子进程结束...
  • 引言 高并发经常会发生在有大活跃用户量...在工作这些年里,我有幸遇到了高并发各种坑,对如何设计高性能接口有一些经验,其实无外乎满足以下几个特点: 灵敏性 伸缩性 容错性 事件驱动/消息驱动 高性能接口设计准则...
  • 文章目录1,Linux下进程间通信机制2,无名管道无名管道特点创建无名管道pipe()无名管道通信无名管道示例 1,Linux下进程间通信机制 Linux下进程间通信机制 应用 早期...
  • 1.1多道程序设计 1.1.1程序顺序执行 ...顺序程序设计方式一些特点 (1)简单,方便,容易理解; (2)确定性:程序运行结果,不会受运行过程中出现中断事件影响; (3)封闭性:运行程序独占整
  • Go最令人感兴趣和新颖的特点是支持并发编程。这是一个大话题,第8章和第9章将专门讨论,所以此处只是简单了解一下Go主要的并发机制、goroutine和通道(channel)。 下一个程序fetchall和前一个一样获取URL的内容,...
  • 文章目录1,线程概念2,线程特点3,线程共享资源--私有资源4,Linux线程库--pthread线程库中提供了如下基本操作a,创建线程pthread_create()b,回收线程pthread_join()c,结束线程pthread_exit()5,线程示例 ...
  • 计算有两个特点:第一,计算是确定,即只要输入相同,程序执行后得到结果总是一样;第二,程序在任意时刻只做一件事,不能同时做多件事。这是传统程序的典型特征。 不属于典型形式计算形式:一种是能够处理...
  • Go语言程序设计

    2018-06-09 11:29:11
    《Go语言程序设计》是Go语言程序基础教程,其特点是从基本语法讲起,并结合Go标准库列举了大量实例。...主要内容包括数据类型、控制结构、数组切片和字典、函数、结构体和方法、接口、并发程序设计、网络编程等。
  • 掌握进程的概念、进程间通信的基本原理、集成间通信的主要类型和各自的特点。实验内容:在linux平台上实现1个父进程、2个子进程,利用管道和共享内存实现两个子进程之间数据快速传送。 3.Windows平台上的TCP并发服务...
  • 按照程序设计的成分性质,有顺序程序设计、并发程序设计、并行程序设计、分布式程序设计之分。按照程序设计风格,有逻辑式程序设计、函数式程序设计、对象式程序设计之分。 编辑本段规范  程序设计的基本概念有程序...
  • 文章目录1,守护进程2,守护进程的特点3,会话、控制终端4,守护进程创建,五个步骤a,创建子进程,父进程退出fork(),exit()b,子进程创建新会话setsid()c,更改当前工作目录chdir()d,重设文件权限掩码umask()e,...
  • 主要介绍了C#程序中的单线程与多线程设计的简单对比,通过实际的代码演示可以清晰看出多线程并发来避免单线程阻塞问题的特点,需要的朋友可以参考下
  • 我们在需要开发一个服务器程序时,有较多的的程序设计...本文所设计的服务器主要是指基于TCP的服务器并发服务器程序设计的两类变体:1.预先派生子进程:让服务器在启动阶段调用fork创建一个子进程池。每个客户请求...
  • 程序设计的惯用手法

    2011-10-24 15:19:12
    其实每个公司都有自己的特色,所以入职后,多看公司代码,一来可以快速的理解代码从而胜任工作,二来可以学习一些惯用手法,例如电信设备有电信设备代码的特点,互联网行业有大并发大规模数据处理等,所以你需要去...
  • 主要有以下特点: 开发简单,代码和项目集中式管理; 运维简单,节省维护成本 排查问题简单,方便问题定位 当项目规模变大时,也会遇到以下问题: 容易形成瓶颈,当所有功能处于一个程序中,请求量变大后,容易...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 897
精华内容 358
关键字:

并发程序设计的特点