嵌入式软件开发培训笔记——linux进程、线程及进程间通信

来源:互联网 发布:java实现aes加密解密 编辑:程序博客网 时间:2024/05/01 20:32
进  程
一、进程基础
   1、 进程与程序区别:1)存放位置 2)动态与静态 3)程序只能有一个,但进程可以有多个
    
    id 为1的进程是init相关

    2、进程类型:交互进程、批处理进程、守护进程
    进程运行状态:运行态、等待态、停止态、死亡态
    
    其中等待态,不可中断指的是不可信号中断,中断分硬中断、软中断及信号中断。
    停止态应理解为暂停态,如GDB调试中设置断点;僵尸态指进程结束,但记录相关信息的struct task_struct还未被删除,所以被称为僵尸态。消除僵尸态有三种方法:1)由父进程回收 2)父进程创建子进程前通知内核在子进程结束时不进行回收,此时由内核去处理 3)父进程在子进程之前先over了,此时由init进程老祖宗进行处理。那么,这三种情况都不满足时——僵尸进程就一直在内核里面。

    3、进程的模式:1)用户模式 2)内核模式
    
二、进程相关的操作命令
    ps、top、kill、{jobs,&,ctrl+Z,bg,fg}
    jobs    显示后台运行的进程
    &        命令后加此符号,使得该进程在后台运行
    ctrl+z  将当前进程切换到后台运行,但切换后进程状态为停止态  
    bg       将后台停止态进程改为后台运行态
    fg        将后台运行态进程切换至前台运行
三、进程基本系统调用
    1、fork函数
    SYNOPSIS
       #include <unistd.h>
       pid_t fork(void);
\\
    2、exec函数
    SYNOPSIS
       #include <unistd.h>

       extern char **environ;

       int execl(const char *path, const char *arg, ...);
       int execlp(const char *file, const char *arg, ...);
       int execle(const char *path, const char *arg,
                  ..., char * const envp[]);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                  char *const envp[]);


        3、exit函数(_exit函数)
SYNOPSIS
       #include <stdlib.h>

       void exit(int status);
SYNOPSIS
       #include <unistd.h>
       void _exit(int status);
       #include <stdlib.h>
       void _Exit(int status);

区别   exit 为库函数   处理时会先对i/o缓冲进行fflush操作     _exit为系统调用函数

        4、wait函数
    SYNOPSIS
       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);

       pid_t waitpid(pid_t pid, int *status, int options);

       int  waitid(idtype_t  idtype,  id_t  id,  siginfo_t  *infop, int
       options);

四、linux守护进程
    也就是通常所说的Daemon进程,是linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。
    守护进程常常在系统启动时开始运行,在系统关闭时终止。
    linux系统有很多守护进程,大多数服务都是用守护进程实现的。
    ps -xja 显示与终端不相关的进行,一般用一查看守护进程

    ps -eLf | grep syslogd
    Linux守护进程编写步骤
    1、创建子进程,父进程退出
    2、在了进程中创建新会话
    3、改变当前目录为根目录
    4、重设文件权限掩码    
    5、关闭文件描述符

线  程
一、线程基础
         多任务处理是指计算机同时运行多个顺序执行流的能力。 
         传统多任务操作系统中一个可以独立调度的任务(或称之一顺序执行流)是一个进程。每个程序加载到内存后只可以唯一地对应创建一个顺序执行流,即传统意义上的进程。每个进程的全部系统资源是私有的,如虚拟地址空间,文件描述符和信号处理等等。使用多进程实现多任务应用时存在如下问题:
         (1)任务切换,即进程间上下文切换时,系统开销比较大。
         (2)多任务之间的协作比较麻烦,涉及进程间通讯。
    1、线程的基本概念:
         为了提高性能,现代多任务操作系统的基本独立可调度任务(或称之一顺序执行流)由线程所替代。每个程序加载到内存后只可以对应创建一个或多个顺序执行流,该执行流我们称之为线程。线程基于进程发展而来,相关联的线程属于同一个进程。在同一个进程中创建的线程共享该进程的虚拟地址空间。使用多线程实现多任务应用时有如下优势:
         (1)基于线程的多任务切换的系统开销较进程切换较小
         (2)线程创建的速度较进程创建要快
         (3)基于线程的多任务协作,即线程间通讯非常方便
        查看线程命令:ps -L
         线程与进程区别:
    2、linux实现线程的基本方式
    3、linux线程库简介——NPTL
二、线程库基本API

1、创建线程
SYNOPSIS
       #include <pthread.h>
       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
       Compile and link with -pthread.
2、结束线程
SYNOPSIS
       #include <pthread.h>
       void pthread_exit(void *retval);
       Compile and link with -pthread.
3、线程回收
SYNOPSIS
       #include <pthread.h>
       int pthread_join(pthread_t thread, void **retval);
       Compile and link with -pthread.
4、向内核发出取消线程的请求
SYNOPSIS
       #include <pthread.h>
       int pthread_cancel(pthread_t thread);
       Compile and link with -pthread.
三、线程的互斥与同步
    1、互斥与同步基本概念
        1)临界资源:某些资源来说,其在同一时间只能被一段机器指令序列所占用。这些一次只能被一段指令序列所占用的资源就是所谓的临界资源。
        2)临界区:对于临界资源的访问,必须是互斥进行。也就是当临界资源被一个指令序列占用时,另一个需要访问相同临界资源的指令序列就不能被执行。指令序列不能执行的实际意思就是其所在的进程/线程会被阴塞。所以我们定义程序访问临界资源的代码序列被称为临界区。
        3)互斥:是指同时只允许一个访问者对临界资源进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
        4)同步:是指在互斥的基础上,通过其它机制实现访问者对资源的有序访问。
    2、互斥与同步API
    (1)线程库同步API
SYNOPSIS        //初始化信号量
       #include <semaphore.h>

       int sem_init(sem_t *sem, int pshared, unsigned int value);

       Link with -lrt or -pthread.

SYNOPSIS        //p操作 (申请资源)常规用int sem_wait(sem_t *sem);

       #include <semaphore.h>

       int sem_wait(sem_t *sem);

       int sem_trywait(sem_t *sem);

       int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

       Link with -lrt or -pthread.

SYNOPSIS        //v操作 (释放资源)
       #include <semaphore.h>

       int sem_post(sem_t *sem);

       Link with -lrt or -pthread.

    (2)线程库互斥API
SYNOPSIS        //初始化信号锁
       #include <pthread.h>
       int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);

        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

SYNOPSIS        //销毁互斥锁
       int pthread_mutex_destroy(pthread_mutex_t *mutex); 
      
SYNOPSIS        //申请互斥锁
       #include <pthread.h>
       int pthread_mutex_lock(pthread_mutex_t *mutex);

SYNOPSIS        //释放互斥锁
       #include <pthread.h> 
       int pthread_mutex_unlock(pthread_mutex_t *mutex);

关于操作系统——多任务同步典型案例

进  程  间  通  信(IPC---Inter Processes Communication)
    1、经典进程间通信方式
        (1)无名管道---pipe
            a)pipe的特点
        这里所说的管道主要指无名管道,它具有如下特点:
        只能用于具有亲缘关系的进程之间的通信;
        半双工的通信模式,具有固定的读端和写端。
        管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数
            b)pipe的创建和打开方式
SYNOPSIS
       #include <unistd.h>
       int pipe(int pipefd[2]);
       #define _GNU_SOURCE             /* See feature_test_macros(7) */
       #include <unistd.h>
       int pipe2(int pipefd[2], int flags);

            c)pipe的读写
        (2)有名管道---FIFO
            FIFO的特点以及FIFO和pipe的区别
            FIFO的创建和打开方式
SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>
       int mkfifo(const char *pathname, mode_t mode);

            FIFO的读写
        (3)信号--------Signal
    信号通信
    信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
    信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
    如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
    a)signal的内核表示

    b)signal的生命周期

c)linux的信号列表

d)linux的信号相关系统调用

man 7 signal

SYNOPSIS        //发送信号
       #include <sys/types.h>
       #include <signal.h>
       int kill(pid_t pid, int sig);

SYNOPSIS
       #include <signal.h>
       int raise(int sig);

SYNOPSIS
       #include <unistd.h>
       unsigned int alarm(unsigned int seconds);

SYNOPSIS
       #include <unistd.h>
       int pause(void);

SYNOPSIS
       #include <signal.h>
       typedef void (*sighandler_t)(int);
       sighandler_t signal(int signum, sighandler_t handler);

    2、AT&T System V IPC
        (1)SysV IPC对象
            IPC对象,IPC标识(id)和IPC键(key)
            IPC对象的创建



       (2)SysV共享内存---Share Memory
            内核实现机制
            相关系统调用
    a)概念
    共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。
    为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。
    进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高效率。
    由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。
    b)实现步骤
    创建/打开共享内存—>映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
—>撤销共享内存映射
—>删除共享内存对象
SYNOPSIS
       #include <sys/ipc.h>
       #include <sys/shm.h>
       int shmctl(int shmid, int cmd, struct shmid_ds *buf);

SYNOPSIS
       #include <sys/ipc.h>
       #include <sys/shm.h>
       int shmget(key_t key, size_t size, int shmflg);

SYNOPSIS
       #include <sys/types.h>
       #include <sys/ipc.h>
       key_t ftok(const char *pathname, int proj_id);

SYNOPSIS
       ipcs [-asmq] [-tclup]
       ipcs [-smq] -i id
       ipcs -h

SYNOPSIS
       ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...
       deprecated usage
       ipcrm {shm|msg|sem} id...

        (3)
SysV消息队列---Message Queue
            Sys信号要和POSIX信号量的比较
            内核实现机制
 
            相关系统调用
           
        (4)
SysV信号灯------Semaphore
            内核实现机制
            相关系统调用
    3、BSD基于套接字(SOCKET)的进程间通信机制
        见网络
0 0
原创粉丝点击