Linux系统编程1
Linux
系统编程
基础知识
- 使用
man
命令,可以查看Linux
手册,man
是manual
的命令缩写,其中文意思就是手册
的意思。 - 我们要查看一个
命令
或函数
的使用方法,我们就可以使用man 命令
或man 函数
- 例如:我们要查看
getpid
的用法,就可以执行man getpid
,就可以查看手册中getpid
这个函数的用法
-
在
OS
中进程是一个非常重要的概念,之后能让我们更方便理解进程,我们就先介绍另一个命令pstree
,这个命令我们用来查看操作系统的进程树。我们可以使用进程树
来辅助理解或者调试一些程序。pstree
这个命令有一些相关的参数,接下来介绍一些常用的参数。-p
:输出进程树,并且会输出进程号-a
:显示进程树,并且显示每个进程对应的目录文件
-
接下来我们使用
pstree -p
命令查看一下具体的进程树:
fork()函数
- 在理解
fork
函数之前我们先需要介绍一下进程,在操作系统中我们在运行中的程序就相当于一个进程,而每个进程都会有一个进程号(pid),并且进程具有树状关系,一个进程可以创建一个新进程,而这个新进程就相当于是该进程的一个子进程。 - 在一个进程中,我们可以使用
getpid()
获取当前进程所对应的进程号,我们还可以使用getppid()
获取当前进程所对应父进程的进程号。
线程相关
pthread_create()函数
-
会详细介绍
pthread_create
函数还会详细介绍pthread_join()
函数 -
pthread_create()
,这个函数是Linux系统提供的一个函数,作用是在当前进程中创建一个线程。接下来说明一下这个函数是如何使用的。- 首先要使用这个函数,首先要包含头文件
#include<pthread.h>
。 - 使用
gcc
编译链接的时候还需要使用-pthread
命令来进行编译。 - 这个函数的功能:在我们调用
pthread_create()
函数的进程中,就会在该进程中调用一个线程。这个线程会开始执行下面pthread_create()
函数中第3
个参数(即函数指针)指向的函数。 - 注意:被指向的函数也有要求,这个函数参数要求传递
void *
,返回值也要求是void *
,但是这并不意味着这个函数没有传递参数,具体请看下面例子,即指向void
类型的指针。这个指针所指向的函数就是我们线程要执行的内容。
- 首先要使用这个函数,首先要包含头文件
-
现在说明一下这个函数的
参数
和返回值
:pthread_t类型
:实际上该类型就是一个无符号整型
,只是使用了这个语句进行定义typedef unsigned long int pthread_t;
pthread_t *thread
:传入的是一个指向线程ID
的指针。这也就是说,我们可以自定义线程ID
,并不像创建一个子进程,这个进程号是系统给的。pthread_attr_t *attr
:pthread_attr_t
是一个结构体,所以*attr
是结构体类型的指针,其指向的是pthread_attr_t
。这个结构体指针,这个参数就是用来决定新线程的属性。如果该线程没有属性,就使用NULL
作为参数。void *(*start_routine)(void *)
:start_routine
是一个函数指针,这个指针指向的函数地址就是线程要执行的内容。void *arg
:传递给线程函数的参数,没有任何参数就填NULL
- 返回值:创建成功就会返回
0
,创建失败就会返回一个特定的非零值
。
1 | int pthread_create |
level_1
- 接下来举一个例子:
- 就是创建一个线程,使得线程执行
thread_function
- 但是这个代码的执行结果不符合我们的预期,原因是进程创建完线程就结束了,进程结束会导致线程也被终止,线程是依赖于进程的,其资源属于进程
- 所以这时我们需要在创建完线程后,让进程执行
while
循环,以确保进程不结束,这样就得到了预期结果
- 就是创建一个线程,使得线程执行
1 | // gcc 6_thread,c -pthread |
level_2
- 但是这个代码还是有问题,因为线程进入死循环了,现在我们继续修改这个代码,使得线程有限次循环。
- 但是还会出现问题,这个线程结束后进程还会在等待中,这样程序一直不会结束
1 | // gcc 6_thread,c -pthread |
level_3
- 接下来我们继续改进该程序,使得进程能够接受到线程结束。这个时候需要使用到
pthread_join()
这个函数。- 这个函数就是等待我们创建的线程结束。线程结束,这个函数将立刻返回;线程没结束,这个函数将阻塞进程。
- 这个函数有两个参数和
int
类型的返回值int pthread_join(pthread_t thread, void **retval);
pthread_t thread
:线程ID
,pthread_join
要等待什么线程结束void **retval
:结束状态
,如果这个指针不是空指针,将保存目标线程的退出状态,如果不想保存就使用NULL
返回值
:调用成功返回0
- 接下来继续优化代码:
1 | // gcc 6_thread,c -pthread |
level4
-
接下来我们继续改进该程序,让我们的进程指定线程循环的次数。这时就需要用上
pthread_create()
函数的最后一个参数* argv
-
但是如果我们按照正常指针来使用这个参数,在编译的时候就会发生错误,因为传递的是
void
类型的指针,这时需要转换为整型
类型的指针
- 最终代码如下:
1 | // gcc 6_thread,c -pthread |
多线程
线程之间通信
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!