操作系统 Linux操作系统编程开发

Posted 石斛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作系统 Linux操作系统编程开发相关的知识,希望对你有一定的参考价值。

Linux操作系统编程开发

预备知识:

  1、进程操作:Linux系统是多任务的操作系统,采用进程作为任务调度的单位,进程在Linux系统下的概念是程序代码的一次执行,包括运行的代码和运行需要的数据、参数等资源。

  2、进程和程序的区别:一方面:在Linux系统下,进程是程序代码的执行,所以程序是一段运行的,有生命力的程序,是一个动态的概念;一个程序是指储存在磁盘或者其他存储介质中的静态代码。另一方面:一个进程是基于一个程序运行的,而一个程序可以被重复载入到内存,形成多个进程!

  3、CPU时间片(Linux系统大约1ms):时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。

  4、Linux系统中进程在宏观上是并行,在微观上是串行的(一个CPU)。在宏观上是并行:同时可以打开多个进程;每个进程都有一个时间片和优先级。在微观上是串行:在每一个CPU时间片中,每个进程都有机会运行,优先级高的进程被运行的概率更大。如果时间片结束,进程还在运行,CPU将剥夺并分配给另一个进程;如果进程在时间片结束之前结束或者进入阻塞状态,CPU立即进行切换!一个CPU,一次只能执行程序的一部分。

  5、mmu和多进程系统:

  6、PID(进程号Process ID):在Linux系统中,每个进程都有一个进程号(PID),所有的进程使用树状结构组织。Linux系统启动时第一个进程是根进程该进程进一步调用系统其它进程。Linux系统中,进程之间有一个明显的继承关系,所有进程都是 PID 为1的 init 进程的后代。

  7、父进程和子进程:Linux系统中每个进程必有一个父进程,相应的,每个进程也可以由零个或者多个子进程。拥有同一个父进程的所有进程被称为兄弟。进程之间的关系存放在进程描述符 task_struct 中。每个 task_struct 都包含一个指向其父进程 task_struct 的指针 parent,还有一个被称为 children 的子进程链表。  

  8、一个线程可以创建和撤销另一个线程,同一个进程中的多个线程并发运行

  9、现存进程、交换进程、init进程、精灵进程

  10、僵尸进程、孤儿进程

  11、进程环境:

  12、进程描述符:

  13、组识别码(gid-Group ID):每个登录的用户至少都会取得两个ID,一个是用户ID(UserID,简称UID),一个是用户组ID(Group ID,简称GID);每一个文件都会有所谓的所有者ID与用户组ID。

  14、PCB(progress control block-进程控制块),系统通过PCB,描述进程和控制进程。在Linux系统下,PCB是 task_struct结构体

  15、进程内存分配示意图(32位操作系统):内核空间和用户空间,内核空间则为所有进程以及内核所共享

  

Linux操作系统进程函数:

1、fork/vfork创建子进程

2、exec系列函数execv/execl、execp/execlp、execve/execle;用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID,它将进程创建与加载一个新进程映象分离

  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 execve(const char *path, const char *argv[], char * const envp[]);

说明:

path参数表示你要启动程序的名称包括路径名

file参数表示命令的文件名

arg参数表示启动程序所带的参数,一般第一个参数为要执行命令名,不是带路径且arg必须以NULL结束

argv参数是需要传递给命令的参数,该数组以NULL结束

envp参数是环境变量数组

3、getpid、getppid:获取进程码

4、setpgid:设置指定进程的组识别码;getpgid:获取指定进程组识别码;(setpgrp、getpgrp是参数为0的特殊情况)

5、setpriority:设置指定进程、进程组、用户的优先级别;getpriority:获取指定进程(进程号)、进程组(识别码)、或者用户(用户ID)的优先级,优先级是-20~20之间的整数,数值越大优先级越高

6、wait/waitpid:暂停当前进程,等待子进程的中断或结束。wait、参数说明pid_t wait(int *status),status保存子进程中断或结束的状态,可设为NULL,返回值为中断或结束的子进程的进程号。waitpid参数说明pid_t waitpid(pid_t pid,int *status,int options) pid:-1表示任何子进程,0:组识别码相同的所有子进程;status保存子进程中断或结束的状态,可设为NULL;options;0;WNOHANG(若无子进程结束则立即返回)、WUNTRACED(若子进程暂停则立即返回);WNOHANG | WUNTRACED(两者取或),

7、进程终止函数:

  _exit:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构。exit() 函数与 _exit() 函数的最大区别在于exit()函数在调用exit系统调用前要检查文件的打开情况,把文件缓冲区中的内容写回文件,也就是“清理I/O缓冲”。

  atexit:ISO C的规定,一个进程可以登记多至32个函数,这些函数将由exit自动调用,这些函数为被称为终止处理函数,并调用atexit函数来登记这些函数。

  on_exit:

 

Linux操作系统信号量及操作函数:

预备知识:

0、临界区同一时刻只能有一个进程执行其中代码的代码段。死锁:某个进程修改了信号量而进入临界区之后,因为崩溃或被“杀死(kill)",却而没有退出临界区,其他被挂起在信号量上的进程永远得不到运行机会。

1、资源互斥和资源同步。资源互斥:指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性,例如死锁:进程甲占用资源A,申请资源B,进程乙占用资源B,申请资源A就会造成一种资源互斥情况“死锁”;资源同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问

2、相交进程之间的关系主要有两种,同步与互斥。

3、处理资源的互斥与同步的几种方式: 自旋锁,信号量,互斥锁与原子变量

 4、信号量是一种能够有效处理进程之间资源互斥和同步的锁机制,信号量是一个计数器一个信号量表示可用资源的个数。信号量的两种操作,P和V:P,等待信号量,当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行(进程运行需要资源)。V,发送信号量,将信号量值加1,(产生资源的进程)

5、Linux系统下的通讯机制(IPC):管道、消息队列、信号、信号值、共享内存(最快的IPC方式)、共享映射文件、套接字(不同机器之间的进程进行通讯)等。

6、信号量集合机制多个进程(队列结构)要分别获得多个临界资源(信号量数组)后方能运行,这就是信号量集合机制。如果进程被挂起,Linux 必须保存信号量的操作状态并将当前进程放入等待队列(sem_queue)。

7、线程占用的资源共享的内存,匿名管道,malloc出来的空间、socket描述符、epoll描述符和线程锁等。

注:2019年10月26日18:07:53,线程的资源是指那些?资源和虚拟内存的关系是什么?为什么资源不能同时被不同的进程占用,而要释放呢?不能通过不同的进程使用不同的指针调用,而且每个进程的虚拟空间(除去共享的内核空间)都是独立的,将程序加载到内存中,然后放入寄存器中,这个加载到的内存不是独立的码?那倒是因为寄存器是唯一的,所以会有资源互斥?个人理解,数据结构实现上,信号是通过字典,键和值是信号集。

8、信号量的数据结构(sem):

 

struct sem {

  int  semval;         /* 信号量的当前值  */

           int   sempid;         /*在信号量上最后一次操作的进程识别号 *                    

        };

 

9、信号量集的数据结构(sem_ds):

struct semid_ds {

  struct ipc_perm sem_perm;          /*  IPC权限 */

   long        sem_otime;        /* 最后一次对信号量操作(semop)的时间 */

  long        sem_ctime;        /* 对这个结构最后一次修改的时间 */

  struct sem      *sem_base;      /* 在信号量数组中指向第一个信号量的指针 */

   struct sem_queue *sem_pending;       /* 待处理的挂起操作*/

  struct sem_queue **sem_pending_last; /* 最后一个挂起操作 */

  struct sem_undo *undo;          /* 在这个数组上的undo 请求 */

  ushort          sem_nsems;           /* 在信号量数组上的信号量号 */

   };

10、系统中每一信号量集合的队列结构(sem_queue

 

struct sem_queue {   

    struct sem_queue * next;   /* 队列中下一个节点 */

    struct sem_queue **    prev;   /* 队列中前一个节点, *(q->prev) == q */

    struct wait_queue *    sleeper;    /* 正在睡眠的进程 */

    struct sem_undo *  undo;   /* undo 结构*/

    int            pid;    /* 请求进程的进程识别号 */

    int            status; /* 操作的完成状态 */

    struct semid_ds *  sma;    /*有操作的信号量集合数组 */

    struct sembuf *    sops;   /* 挂起操作的数组 */

    int    nsops;  /* 操作的个数 */

};

 

11、三种数据结构的关系

 

 

 

信号量操作的函数(系统调用):

1、semget ( key_t key, int nsems, int semflg ),创建并打开一个信号集

2、semop ( int semid, struct sembuf *sops, unsigned nsops),根据索引值,对指定的信号量进行指定的操作(P、V操作)

一、sops参数指向类型为sembuf的一个数组

struct sembuf {

                ushort  sem_num;        /* 在数组中信号量的索引值 */

                short   sem_op;         /* 信号量操作值(正数、负数或0) */

                short   sem_flg;        /* 操作标志,为IPC_NOWAIT或SEM_UNDO*/

        };

注:1、sem_op为负数,那么就从信号量的值中减去sem_op的绝对值,这意味着进程要获取资源如果sem_op是正数,把它的值加到信号量,这意味着把资源归还给应用程序的集合

命令(cmd)

解   释

IPC_STAT

从信号量集合上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中

IPC_SET

设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值

IPC_RMID

从内核中删除信号量集合

GETALL

从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中

GETNCNT

返回当前等待资源的进程个数

GETPID

返回最后一个执行系统调用semop()进程的PID

GETVAL

返回信号量集合内单个信号量的值

GETZCNT

返回当前等待100%资源利用的进程个数

SETALL

与GETALL正好相反

SETVAL

用联合体中val成员的值设置信号量集合中单个信号量的值

 

以上是关于操作系统 Linux操作系统编程开发的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向Linux 文件权限 ( Linux 权限简介 | 系统权限 | 用户权限 | 匿名用户权限 | 读 | 写 | 执行 | 更改组 | 更改用户 | 粘滞 )(代码片段

简明Linux系统编程教程上线

C#程序员经常用到的10个实用代码片段 - 操作系统

免费下载全套最新3.Shell编程视频教程+教学资料+学习课件+源代码+软件开发工具

VS2015 代码片段整理

Python 之 Socket编程(TCP/UDP)