Linux系统编程常见函数 (进程/线程)

Lunix系统编程函数多且复杂,本文记录一下Linux系统编程最最常用的哪些函数以及这些函数的常见用法。当然本文不可能囊括所有,所以在编程时候最好的学习方法还是查看manpage,多看多写,熟能生巧。

而且这里只是总结一下函数的最常用的用法和参数,相关知识还是要看书看视频学习的。

博主学习Linux编程不久,水平有限文章有错误还请各位不吝指出。废话不多说,开始咯。

这篇主要归纳进程和线程相关的函数,文件和目录操作看上一篇:https://www.cnblogs.com/clno1/p/12935626.html

进程相关:

fork函数:

pid_t fork(void);   作用是创建一个子进程。

失败返回-1;成功返回:① 父进程返回子进程的 ID(非负) ②子进程返回 0   (亦即我们用fork返回值判断当前是父/子进程)

父子相同处: 全局变量、.data、.text、栈、堆、环境变量、用户 ID、宿主目录、进程工作目录、信号处理方式...

父子不同处: 1.进程 ID 2.fork 返回值 3.父进程 ID 4.进程运行时间 5.闹钟(定时器) 6.未决信号集

父子进程的copyonwrite机制:https://www.pianshen.com/article/4305691855/

getpid函数:

pid_t getpid(void);  作用是获取当前进程 ID(返回值)

getppid函数:

pid_t getppid(void);  获取当前进程的父进程 ID(返回值)

getuid 函数:

获取当前进程实际用户 ID  uid_t getuid(void);

获取当前进程有效用户 ID  uid_t geteuid(void);

getgid 函数

获取当前进程使用用户组 ID  gid_t getgid(void);

获取当前进程有效用户组 ID  gid_t getegid(void);

孤儿进程与讲师进程,以及回收子进程:

https://www.cnblogs.com/clno1/p/12937547.html

守护进程相关: 

 https://www.cnblogs.com/clno1/p/12941308.html

进程间通信:

在操作系统历史中出现了很多IPC,如文件、管道、信号、共享内存、消息队列、套接字、命名管道等。但是现今常用的进程间通信方式有:① 管道 (使用最简单) ,② 信号 (开销最小),③ 共享映射区 (无血缘关系),④ 本地套接字 (最稳定

匿名管道PIPE:

int pipe(int pipefd[2]);   函数作用创建匿名管道。成功:0;失败:-1,设置 errno;

函数调用成功返回 r/w 两个文件描述符。无需 open,但需手动 close。规定:fd[0] → r; fd[1] → w,就像 0对应标准输入,1 对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。

命名管道FIFO:

匿名管道(pipe)只能用于“有血缘关系”的进程间。但通过 FIFO,不相关的进程也能交换数据。FIFO 是 Linux 基础文件类型中的一种。但,FIFO 文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。各

进程可以打开这个文件进行 read/write,实际上是在读写内核通道,这样就实现了进程间通信。

创建方式:1. 命令:mkfifo 管道名  2. 库函数:int mkfifo(const char *pathname, mode_t mode); 成功:0; 失败:-1

一旦使用 mkfifo 创建了一个 FIFO,就可以使用 open 打开它,常见的文件 I/O 函数都可用于 fifo。如:close、read、write、unlink 等

共享映射区MMap:

原理是将一个磁盘文件映射到内存地址空间缓冲区,于是当从缓冲区中取数据,就相当于读文件中的相应字节。于此类似,将数据存入缓冲区,则相应的字节就自动写入文件。

mmap 函数
void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);  函数作用是建立映射文件。
返回:成功:返回创建的映射区首地址; 失败:MAP_FAILED 宏
addr: 建立映射区的首地址,由 Linux 内核指定。使用时,直接传递 NULL
length: 欲创建映射区的大小
prot: 映射区权限 PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
flags: 标志位参数(常用于设定更新物理区域、设置共享、创建匿名映射区)
    MAP_SHARED: 会将映射区所做的操作反映到物理设备(磁盘)上。
    MAP_PRIVATE: 映射区所做的修改不会反映到物理设备。
fd: 用来建立映射区的文件描述符
offset: 映射文件的偏移(4k 的整数倍)

父子等有血缘关系的进程之间也可以通过 mmap 建立的映射区来完成数据通信。但相应的要在创建映射区的时候指定对应的标志位参数 flags:

MAP_PRIVATE: (私有映射) 父子进程各自独占映射区;  MAP_SHARED: (共享映射) 父子进程共享映射区;

munmap 函数

int munmap(void *addr, size_t length);  函数作用是释放刚刚建立映射的内存缓冲区。

返回值: 成功:0; 失败:-1  errno

信号:

 信号重要且相对复杂,开新篇总结:https://www.cnblogs.com/clno1/p/12941316.html

线程相关:

线程(ight weight process)称为轻量级的进程,本质仍是进程(在 Linux 环境下),一个区别在于:进程,独立地址空间,拥有 PCB 。 线程,有独立的 PCB,但没有独立的地址空间(共享)。

线程共享资源  1.文件描述符表  2.每种信号的处理方式  3.当前工作目录  4.用户 ID 和组 ID  5.内存地址空间 (.text/.data/.bss/heap/共享库)

线程非共享资源  1.线程 id  2.处理器现场和栈指针(内核栈)  3.独立的栈空间(用户空间栈)  4.errno 变量  5.信号屏蔽字  6.调度优先级

pthread_create 函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);  创建一个新线程。 其作用,对应进程中 fork() 函数。

返回值:成功:0; 失败:错误号 -----Linux 环境下,所有线程特点,失败均直接返回错误号。

参数:pthread_t:当前 Linux 中可理解为:typedef unsigned long int pthread_t;

参数 1:传出参数,保存系统为我们分配好的线程 ID
参数 2:通常传 NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数
参数 3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数 4:线程主函数执行期间所使用的参数。  (即参数3和4描述了线程的函数)

pthread_self 函数

pthread_t pthread_self(void);   获取线程 ID。其作用对应进程中 getpid() 函数。  返回值:成功:0; 失败:无!

线程 ID:pthread_t 类型,本质:在 Linux 下为无符号整数(%lu),其他系统中可能是结构体实现

线程 ID 是进程内部,识别标志。(两个进程间,线程 ID 允许相同)

注意:不应使用全局变量 pthread_t tid,在子线程中通过 pthread_create 传出参数来获取线程 ID,而应使用pthread_self。

pthread_exit 函数

void pthread_exit(void *retval);  将单个线程退出  参数:retval 表示线程退出状态,通常传 NULL

pthread_join 函数

int pthread_join(pthread_t thread, void **retval);   阻塞等待线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。  成功:0;失败:错误号

参数:thread:线程 ID (【注意】:不是指针);retval:存储线程结束状态。

pthread_detach 函数

int pthread_detach(pthread_t thread);   实现线程分离  成功:0;失败:错误号

线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。

一般情况下,线程终止后,其终止状态一直保留到其它线程调用 pthread_join 获取它的状态为止。但是线程也可以被置为 detach 状态, 这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。

不能对一个已经处于 detach 状态的线程调用 pthread_join,这样的调用将返回 EINVAL 错误。也就是说,如果已经对一个线程调用了 pthread_detach 就不能再调用 pthread_join 了。

也可使用 pthread_create 函数参 2(线程属性)来设置线程分离。

pthread_cancel 函数

int pthread_cancel(pthread_t thread);   杀死(取消)线程 其作用,对应进程中 kill() 函数。  成功:0;失败:错误号

值得注意的是:线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。

取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用 creat,open,pause,close,read,write..... 执行命令 man 7 pthreads 可以查看具备这些取消点的系统调用列表。

可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用 pthread_testcancel函数自行设置一个取消点。


总结:终止某个线程而不终止整个进程,有三种方法:
1. 从线程主函数 return。这种方法对主控线程不适用,从 main 函数 return 相当于调用 exit。
2. 一个线程可以调用 pthread_cancel 终止同一进程中的另一个线程。
3. 线程可以调用 pthread_exit 终止自己。

线程同步:

猜你喜欢

转载自www.cnblogs.com/clno1/p/12935702.html
今日推荐