- pid_t getpid(void)
获取当前进程的pid(processID),进程唯一标识符
- pid_t fork(void)
用于创建一个进程,在内核中操作系统重新为其申请了一个PCB,复制父进程的所有数据,执行和父进程相同的操作,子进程和父进程唯一区别——pid不同
- fork函数有两个返回值,如果fork成功,子进程中fork的返回值是0, 父进程中fork的返回值是子进程的pid,通过这样的方式来区分父子进程。派生子进程的进程,即父进程,其pid不变;
- 对子进程来说,fork返回给它0,但它的pid绝对不会是0;之所以fork返回0给它,是因为它可以调用getpid()来获取自己的pid;
- fork之后父子进程除非采用了同步手段,否则不能确定谁先运行,也不能确定谁先结束。认为子进程结束后父进程才从fork返回的,这是不对的,fork不是这样的,vfork才这样。
- pid_t wait(int *stat_loc)
- pid_t waitpid(pid_t pid, int *stat_loc, int options)
wait()函数用于使父进程阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()函数就会立即返回
waitpid()的作用和wait()一样,但它可以指定需要等待终止的子进程,它还有若干选项,如可提供一个非阻塞版本的 wait()功能,也能支持作业控制。实际上,wait()函数只是 waitpid()函数的一个特例,在Linux 内部实现 wait()函数时直接调用的就是waitpid()函数。
所需头文件 | #include<sys/wait.h> | |
参数说明 | pid | pid>0:只等待进程ID等于pid的子进程,不管是否已经有其它子进程退出,只要指定的子进程还没有结束,waitpid()就会一直等待下去 |
pid=-1:等待任何一个子进程退出,此时作用等同于wait() | ||
pid=0:等待其组ID等于调用进程组ID的任一子进程 | ||
pid<1:等待其组ID等于pid的绝对值的任一子程序 | ||
stat_loc | 这里的stat_loc是一个整形指针,是该子进程退出时的状态。若stat_loc不为空,可以通过它来获取子进程的退出状态。子进程的退出状态可以由Linux中特定的宏来测定 | |
options | WNOHANG:若由pid指定的子进程没有结束,则waitpid()不阻塞而立即返回,此时返回值为0 | |
WUNTRACED:为了实现某种操作,由pid指定的的任一子进程已被暂停,且其状态自暂停以来还未报告过,则返回其状态 | ||
0:同wait(),阻塞父进程,等待子进程退出 | ||
函数返回值 | 正常:已成功结束运行的子进程进程号 使用选项WNOHANG 且没有自进程退出:0 失败:-1 |
- mode_t umask(mode_t mask)
功能 | 设置了用户创建文件的默认权限 |
mask | 格式:XXX |
返回值 | 成功:已成功结束运行的子进程的pid 失败:-1 |
注:umask设置了用户创建文件的默认权限,它与chmod的效果刚好相反,umask设置的是权限“补码”,而chmod设置的是文件权限码,umask是从权限中“拿走”相应的位,且文件创建时不能赋予执行权限;
umask 命令允许你设定文件创建时的缺省模式,对应每一类用户(文件属主、同组用户、其他用户)存在一个相应的umask值中的数字。对于文件来说,这一数字的最大值分别是6。系统不允许你在创建一个文本文件时就赋予它执行权限,必须在创建后用chmod命令增加这一权限。目录则允许设置执行权限,这样针对目录来说,umask中各个数字最大可以到7;
在使用umask命令之前一定要先计算清楚所需的权限掩码。否则可能会得到一些非常奇怪的结果;例如,如果将umask值设置为6 0 0,那么所创建的文件/目录的缺省权限就是0 6 6!
-
exec函数族
exec函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。
使用exec函数族主要有两种情况:
(1)当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。
(2)如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程。
exec函数族共有6种不同形式的函数。这6个函数可以划分为两组:
- execl、execle和execlp
- execv、execve和execvp
这两组函数的不同在于exec后的第一个字符,第一组是l,在此称为execl系列;第二组是v,在此称为execv系列。这里的l是list(列表)的意思,表示exec1系列函数需要将每个命令行参数作为函数的参数进行传递;而v是vector(矢量)的意思,表示execv系列函数将所有函数包装到一个矢量数组,即就是数组指针中传递即可。
后缀 | 操作能力 |
l | 希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志 |
v | 希望接收到一个以NULL结尾的字符串数组的指针 |
p | 是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件 |
e | 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境 |
exec函数的原型如下:
- int execl(const char *path,const char * arg,…);
- int execle(const char *path,const char * arg,char * const envp[]);
- int execlp(const char * file,const char * arg,…);
- int execv(const char * path,char * const argv[]);
- int execve(const char * path,char * const argv[],char * const envp[]);
- int execvp(const char * file,char * const argv[]);
参数说明:
path:要执行的程序路径。可以是绝对路径或者是相对路径。在execv、execve、execl和execle这4个函数中,使用带路径名的文件名作为参数。
file:要执行的程序名称。如果该参数中包含“/”字符,则视为路径名直接执行;否则视为单独的文件名,系统将根据PATH环境变量指定的路径顺序搜索指定的文件。
argv:命令行参数的矢量数组。
envp:带有该参数的exec函数可以在调用时指定一个环境变量数组。其他不带该参数的exec函数则使用调用进程的环境变量。
arg:程序的第0个参数,即程序名自身。相当于argv[0]。
…:命令行参数列表。调用相应程序时有多少命令行参数,就需要有多少个输入参数项。注意:在使用此类函数时,在所有命令行参数的最后应该增加一个空的参数项(NULL),表明命令行参数结束。
返回值:-1表明调用exec失败,无返回表明调用成功。
以上函数的功能相同,掌握其中一种即可。
C库文件接口函数
头文件:#include<stdio.h>
- FILE *fopen(const char *path, const char *mode)
功能 | 打开一个文件 | |
path | 指定打开的文件路径及文件名 | |
mode | r | 以只读方式打开文件,该文件必须存在 |
r+ | 以读/写方式打开文件,该文件必须存在 | |
w | 打开只写文件,若文件存在则长度清为 0,即该文件内容消失,若不存在则创建该文件 | |
w+ | 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件 | |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾 | |
a+ | 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后 | |
返回值 | 成功:返回文件指针 失败:NULL |
- int fclose(FILE *fp);
功能 | 关闭一个文件 |
fp | 文件指针 |
返回值 | 成功:0 失败:返回“-1”并输出错误原因 如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF |
注:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
- size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
函数释义:fread函数从stream指向的文件流中,读取nmemb个数据元素(nmemb这里我看成n个memory block 即内存块),每个元素size 字节长,并将这些数据存储到ptr指向的地址里面。
功能 | 从文件流中读取数据 |
ptr | 接受数据的地址 |
size | 每次要读的字节数,单位是字节 |
nmemb | 要读nmemb个数据项,每个数据项size个字节 |
stream | 输入流 |
返回值 | 成功:返回实际读取到的项个数(小于或等于nmemb) 失败:返回 0(读到文件末尾也返回0) |
- size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
函数释义:fwrite函数从ptr指向的地址里面获取nmemb个数据元素,每个size字节长,将这些数据存到stream指向的文件流中。
功能 | 向指定的文件中写入若干数据块 |
ptr | 要写入文件的数据 |
size | 每次要写入的字节数,单位是字节 |
nmemb | 要写nmemb个数据项,每个数据项size个字节 |
stream | 目标文件指针 |
返回值 | 返回实际写入的数据项个数nmemb |
注:
- 写入到文件的哪里? 这个与文件的打开模式有关,如果是w+,则是从file pointer指向的地址开始写,替换掉之后的内容,文件的长度可以不变,stream的位置移动nmemb个数;如果是a+,则从文件的末尾开始添加,文件长度加大.
- fread和fwrite返回读取或写入的数据元素的个数。只有当size等于1的时候,返回的元素个数才与传输的字节数目相等。 如果发生错误,或者到达文件文件末尾,这个返回值就会小于nmemb(当最后一次读取或写入不够nmemb个数据元素时)或者甚至是0 fread函数并不区别是发生了错误还是到达文件尾,则这就需要调用者feof和ferror来判断是不是到达文件尾或者发生了错误.
- fseek对此函数有作用,但是fwrite函数写到用户空间缓冲区,并未同步到文件中,所以修改后要将内存与文件同步可以用fflush(FILE *fp)函数同步.
- int fseek(FILE *stream, long offset, int whence)
函数释义:设置文件指针stream的位置。如果执行成功,stream将指向以whence为基准,偏移offset个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
功能 | 设置文件指针stream的位置 | |
stream | 数据流指针 | |
offset | 偏移量 | |
whence | 文件头(SEEK_SET) | |
当前位置(SEEK_CUR) | ||
文件尾(SEEK_END) | ||
返回值 | 成功:0 失败:-1 |
注:fseek函数和lseek函数类似,但lseek返回的是一个off_t数值,而fseek返回的是一个整型
- long ftell(FILE *stream)
函数释义:在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置。所以使用函数 ftell 易于得到文件位置指针当前位置相对于文件首的偏移字节数,从而确定文件指针当前位置。
功能 | 用于得到文件位置指针当前位置相对于文件首的偏移字节数 |
stream | 数据流指针 |
返回值 | 成功:返回文件位置指针当前位置相对于文件首的偏移字节数 失败:-1 |
注:因为ftell返回long型,根据long型的取值范围—,故对大于2.1G的文件进行操作时出错。
- void rewind(FILE *stream)
功能 | 将文件内部的位置指针重新指向一个流的开头 |
stream | 数据流指针 |
注:不是文件指针而是文件内部的位置指针,随着对文件的读写文件的位置指针(指向当前读写字节)向后移动。而文件指针是指向整个文件,如果不重新赋值文件指针不会改变。
系统调用文件接口函数
头文件:#include<unistd.h>
- int open(const char *pathname, int flags)
- int open(const char *pathname, int flags, mode_t mode)
功能 | 打开和创建文件 | |
pathname | pathname 是待打开/创建文件的POSIX(可移植性操作系统接口)路径名或文件 | |
flags | O_RDONLY | 以只读方式打开文件 |
O_WRONLY | 以只写方式打开文件 | |
O_RDWR | 以可读可写方式打开文件 | |
O_CREAT | 如果指定文件不存在,则创建这个文件 | |
O_APPEND | 每次写操作都写入文件的末尾(即就是追加写入) | |
O_TRUNC | 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容 | |
mode | 仅当创建新文件时(即 使用了O_CREAT 时)才使用,用于指定文件的访问权限位(access permission bits) | |
返回值 | 成功:返回最小的未被使用的描述符 失败:-1 |
- int close(int fd)
功能 | 关闭文件 |
fd | 数据流指针 |
返回值 | 成功:0 失败:-1 |
注:当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。但是对于一个长年累月运行的程序(比如网络服务器),打开的文件描述符一定要记得关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系统资源。
- ssize_t write(int fd, const void *buf, size_t count)
函数释义:write()会把指针buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
功能 | 向指定文件写入数据 |
fd | 数据流指针 |
buf | 读取数据的地址空间 |
count | 写入的字节数 |
返回值 | 成功:实际写入的字节数 失败:-1 |
- ssize_t read(int fd, void *buf, size_t count)
函数释义:read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中
功能 | 从指定文件读取数据 |
fd | 数据流指针 |
buf | 写入数据的地址空间 |
count | 读取的字节数 |
返回值 | 成功:实际读取的字节数。若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。 失败:-1。错误代码存入errno中,而文件读写位置则无法预期。 |
- off_t lseek(int fd, off_t offset, int whence)
功能 | 设置文件的读写指针 | |
fd | 数据流指针 | |
offset | 偏移量 | |
whence | 文件头(SEEK_SET) 将读写位置指向文件头后再增加offset个位移量 | |
当前位置(SEEK_CUR) 以当前的读写位置往后增加offset个位移量 | ||
文件尾(SEEK_END) 将读写位置指向文件尾后再增加offset个位移量 | ||
返回值 | 成功:返回当前的读写位置 失败:-1 |
注:对于普通文件(regular file),cfo(current file offset)是一个非负整数。但对于特殊设备,cfo 有可能是负数。因此,我们不能简单地测试 lseek 的返回值是否小于 0 来判断 lseek 成功与否,而应该测试 lseek 的返回值是否等于 -1 来判断 lseek 成功与否。
如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定的。
- int truncate(const char *path, off_t length)
函数释义:truncate()会将参数path指定的文件大小改为参数length指定的大小。 如果原来的文件大小比参数length大,则超过的部分会被删除
功能 | 修改指定文件大小 |
path | 要修改的文件路径或文件名 |
length | 修改后的文件大小 |
返回值 | 成功:0 失败:-1 |
头文件:#include<stdio.h>
- int fileno(FILE *stream)
函数释义:fileno()用来取得参数stream指定的文件流所使用的文件描述符
功能 | 取得参数stream指定的文件流所使用的文件描述符 |
stream | 数据流指针 |
返回值 | 成功:数据流的文件描述符 失败:-1 |
- void clearerr(FILE *stream)
函数释义:clearerr的作用是使文件错误标志和文件结束标志置为0.假设在调用一个输入输出函数时出现了错误,ferror函数值为一个非零值。在调用clearerr(fp)后,ferror(fp)的值变为0。
功能 | 复位错误标志 |
stream | 数据流指针 |
头文件#include <unistd.h>
- int dup(int oldfd)
- int dup2(int oldfd, int newfd)
功能 | 两个均为复制一个现存的文件的描述 |
oldfd | 目标文件的文件描述符的值 |
newfd | 指定新的文件描述符的值 |
返回值 | 成功:数据流的文件描述符 失败:-1 |
注:dup()返回的文件描述的值一定是当前可用文件描述符当中的最小值;dup2()可以用newfd指定新描述符的值,如果newfd本身已经打开了,则会先将其关闭。如果newfd等于oldfd,则返回newfd,并不关闭它。
进程间通信相关函数
-
管道(pipe)
头文件:#include <unistd.h>
- int pipe(int pipefd[2])
功能 | 创建一个匿名管道 |
pipefd[0] | 管道的写入端 |
pipefd[1] | 管道的读取端 |
返回值 | 成功:0 失败:-1 |
- int mkfifo(const char *pathname, mode_t mode)
功能 | 创建一个命名管道 |
pathname | 命名管道文件路径名 |
mode | 文件权限 |
返回值 | 成功:0 失败:-1 |
注:mkfifo ()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限,因此 umask值也会影响到FIFO文件的权限。
- key_t ftok(const char *pathname, int proj_id)
头文件: #include <sys/ipc.h>
功能 | 系统建立IPC通讯 (消息队列、信号量和共享内存)时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。 |
pathname | 文件名 |
proj_id | 子序号。虽然是int类型,但是只使用8bits(1-255) |
返回值 | 成功:文件的inode结点号加上子序号(16进制数) 失败:-1 |
Linux进程通信(IPC)之共享内存
共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。
- int shmget(key_t key, size_t size, int shmflg)
功能 | 得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符 |
key | ftok返回的IPC键值 |
size | 新建的共享内存大小,以字节为单位 |
shmflg | 共享内存权限标志。它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作(例如:IPC_CREAT | 0664). |
返回值 | 成功:返回共享内存的标识符 失败:-1 |
- void *shmat(int shmid, const void *shmaddr, int shmflg)
功能 | 连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问 |
shmid | 共享内存的标识符 |
size | 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置 |
shmflg | SHM_RDONLY:为只读模式,其它为读写模式 |
返回值 | 成功:映射首地址 失败:((void*)-1) |
- int shmdt(const void *shmaddr)
功能 | 与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存,也就是断开映射 |
shmaddr | 映射首地址 |
返回值 | 成功:0 失败:-1 |
- int shmctl(int shmid, int cmd, struct shmid_ds *buf)
功能 | 连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问 |
shmid | 共享内存的标识符 |
cmd | IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中 |
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内 | |
IPC_RMID:删除这片共享内存 | |
buf | 共享内存管理结构体,用于获取共享内存的状态信息 |
返回值 | 成功:0 失败:-1 |
信号相关函数
- int kill(pid_t pid, int sig)
- int raise(int sig)
- void abort(void)
功能 | 向进程发送信号 | |
kill | pid | 进程标识符 |
sig | 信号名称 | |
可指定进程和发送的信号 | ||
raise | sig | 信号名称 向当前进程发送指定信号 |
可指定发送的信号 | ||
abort | 向当前进程发送SIGABRT信号 |
- unsigned int alarm(unsigned int seconds)
功能 | 在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号 |
seconds | 定时时间,单位:秒(S) |
返回值 | 成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0 失败:-1 |
注:可以设置忽略或者不捕获此信号,如果采用默认方式其动作是终止调用该alarm函数的进程。一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。需要注意的是,经过指定的秒数后,信号由内核产生,由于进程调度的延迟,所以进程得到控制从而能够处理该信号还需要一些时间。
- int sigqueue(pid_t pid, int sig, const union sigval value)
功能 | 在队列中向指定进程发送一个信号和数据 |
pid | 进程标识符 |
sig | 信号名称 |
value | 是一个联合体,表示信号附带的数据,附带数据可以是一个整数也可以是一个指针,即通常所说4字节值 |
返回值 | 成功:0 失败:-1 |
- sighandler_t signal(int signum, sighandler_t handler)
功能 | 设置某一信号的处理动作 | |
signum | 要设置的信号名称 | |
handler | 自定义函数 | 此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为signum的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:
|
SIG_IGN | 这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号 | |
SIG_DFL | 这个符号表示恢复系统对信号的默认处理 | |
返回值 | 成功:先前的信号处理函数指针 失败:-1 |
注:signum可以为除SIGKILL及SIGSTOP外的任何一 个特定有效的信号
- int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact)
功能 | 为信号重新自定义新的行为,并将原有的行为保存在oldcat中 |
signum | 信号名称 |
act | 定义的信号新行为 |
oldact | 保存信号原来的行为 |
返回值 | 成功:0 失败:-1 |
sigaction结构体定义:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
- sa_handler信号处理程序 不接受额外数据
- sa_sigaction信号处理程序 能接受额外数据,和sigqueue配合使用
- sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置
- sa_restorer 此参数没有使用
- sa_flags 用来设置信号处理的其他相关操作,下列的数值可用
-
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号
-
SA_SIGINFO:当SA_SIGINFO设置时与sa_sigaction 搭配出现,sa_sigaction函数的第一个参数与sa_handler一样表示当前信号的编号,第二个参数是一个siginfo_t 结构体,第三个参数一般不用
当使用sa_handler时sa_flags设置为0即可。
siginfo_t结构体定义:
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since kernel 2.6.32) */
}
注:signal()可能具有一定的内核版本差异性(只是听说,并没有验证), 根据自己对signal()和sigaction()的使用,sigaction()对信号处理更加详细和强大,所以掌握sigaction()是首选。
SIGCHLD:在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程,按系统默认将忽略此信号,如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。
线程
头文件:#include<pthread.h>
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg)
功能 | 创建线程(实际上就是确定调用该线程函数的入口点) |
thread | 指向线程id的指针 |
attr | 设置线程属性,通常设置为NULL |
start_rtn | 线程运行函数的起始地址 |
arg | 运行函数的参数 |
返回值 | 成功:0 失败:-1 |
注:因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread(或-pthread)以显式链接该库。函数在执行错误时的错误信息将作为返回值返回,并不修改系统全局变量errno,当然也无法使用perror()打印错误信息。
- pthread_t pthread_self(void)
功能 | 获得线程自身的id |
返回值 | 线程id |
pthread_t的类型为unsigned long int,所以在打印的时候要使用%lu方式,否则显示结果出问题
- int pthread_cancel(pthread_t thread)
功能 | 发送终止信号给thread线程 |
thread | 线程id |
返回值 | 成功:0 失败:!0 |
注:发送成功并不意味着thread会终止。若是在整个程序退出时,要终止各个线程,应该在成功发送 CANCEL 指令后,使用 pthread_join 函数,等待指定的线程已经完全退出以后,再继续执行。
- int pthread_join(pthread_t thread, void **retval)
函数释义:pthread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。
功能 | 发送终止信号给thread线程 |
thread | 线程id |
retval | 用户定义的指针,用来存储被等待线程的返回值 |
返回值 | 成功:0 失败:错误码 |
- int pthread_detach(pthread_t thread)
函数释义:
创建一个线程默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收,所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。
但是调用pthread_join(pthread_id)后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此,比如在Web服务器中当主线程为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的链接),这时可以在子线程中加入代码pthread_detach(pthread_self)或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。这里需要注意的是,该线程的状态为detached时,就不需要再使用pthread_join函数来等待线程的退出了,因为这时系统会自动地回收资源;否则pthread_join函数将会返回错误码。
功能 | 分离线程 |
thread | 线程id |
返回值 | 成功:0 失败:错误码 |
注:在线程设置为joinable后,可以调用pthread_detach()使之成为detached。但是相反的操作则不可以。还
有,如果线程已经调用pthread_join()后,则再调用pthread_detach()则不会有任何效果
- void pthread_exit(void *retval)
功能 | 终止调用它的线程 |
retval | 返回某个对象的指针 |