实现进程的调度。它的任务是从运行队列rq中找到一个进程,并随后将CPU分配给这个进程
实现多路复用输入/输出模型。原型:
int select(int maxfd, fd_set*rdset, fd_set *wrset, fd_set *exset, struct timeval *timeout);
maxfd, 需要监视的最大的文件描述符值+1;
rdset, 需要检测的可读文件描述符的集合,
wrset, 可写文件描述符的集合及异常文件描述符的集合
exset
structtimeval,描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
FD_ZERO,FD_SET,FD_CLR,FD_ISSET:
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理, 所以结果是不可知的。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
struct timeval结构:
struct timeval{
long tv_sec;//second
long tv_usec;//minisecond
}
timeout设置情况:
null:select将一直被阻塞,直到某个文件描述符上发生了事件。
0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
kmalloc对应于kfree,可以分配连续的物理内存;
vmalloc对应于vfree,分配连续的虚拟内存,但是物理上不一定连续。
vmalloc分配内存的时候逻辑地址是连续的,但物理地址一般是不连续的,适用于那种一下需要分配大量内存的情况,如insert模块的时候。这种分配方式性能不入kmalloc。
kmalloc分配内存是基于slab,因此slab的一些特性包括着色,对齐等都具备,性能较好。物理地址和逻辑地址都是连续的
最主要的区别是
分配大小的问题。
比如你需要28个字节,那一定用KMALLOC,如果用VMALLOC,分配不多次机器就罢工了。
将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。将网络地址转为网络二进制数字,返回的IP地址是网络序的。
函数原型:unsigned long in inet_addr(const char *cp)
原型:intdaemon(int nochdir, int noclose);
参数:当 nochdir为零时,当前目录变为根目录,否则不变;
当 noclose为零时,标准输入、标准输出和错误输出重导向为/dev/null,也就是不输出任何信息,否则照样输出。
返回值:deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息 全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。
使一个线程等待另一个线程结束,代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行
原型: int pthread_join(pthread_t thread, void **value_ptr);
参数: thread:等待退出线程的线程号。
value_ptr:退出线程的返回值。
信号量集得创建与打开
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,则返回信号量集的IPC标识符。
如果失败,则返回-1:errno=EACCESS(没有权限)
EEXIST(信号量集已经存在,无法创建)
EIDRM(信号量集已经删除)
ENOENT(信号量集不存在,同时没有使用IPC_CREAT)
ENOMEM(没有足够的内存创建新的信号量集)
ENOSPC(超出限制)
参数: key, 所创建或打开信号量集的键。
nsems,创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效
semflg,调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过or表示,
IPC_CREAT如果信号量集在系统内核中不存在,则创建信号量集,
如果单独使用IPC_CREAT,则semget()要么返回新创建的信号量集的标识符,要么返回系统中已经存在的同样的关键字值的信号量的标识符;
IPC_EXCL当和 IPC_CREAT一同使用时,如果信号量集已经存在,则调用失败,否则要么返回新创建的信号量集的标识符,要么返回-1。
IPC_EXCL单独使用没有意义
信号量的操作
原型: int semop(int semid,structsembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失败:errno=E2BIG(nsops大于最大的ops数目)
参数: semid: 信号量集引用ID
sops: 指向由sembuf组成的数组
ednsops:数组中的操作的个数
如果sem_op是负数,那么信号量将减去它的值。这和信号量控制的资源有关。如果没有使用IPC_NOWAIT,那么调用进程将进入睡眠状态,直到信号量控制的资源可以使用为止。如果sem_op是正数,则信号量加上它的值。这也就是进程释放信号量控制的资源。最后,如果sem_op是0,那么调用进程将调用sleep(),直到信号量的值为0。这在一个进程等待完全空闲的资源时使用。
信号量的控制
原型:intsemctl(int semid,int semnum,int cmd,union semunarg);
返回值:如果成功,则为一个正数。
如果失败,则为-1:errno=EACCESS(权限不够)
EFAULT(arg指向的地址无效)
EIDRM(信号量集已经删除)
EINVAL(信号量集不存在,或者semid无效)
EPERM(EUID没有cmd的权利)
ERANGE(信号量值超出范围)
参数: semid: 为信号量集引用标志符
semnum: 用于指定某个特定信号量
cmd: 调用该函数执行的操
semunarg:
系统调用semctl用来执行在信号量集上的控制操作。这和在消息队列中的系统调用msgctl是十分相似的。但这两个系统调用的参数略有不同。因为信号量一般是作为一个信号量集使用的,而不是一个单独的信号量。所以在信号量集的操作中,不但要知道IPC关键字值,也要知道信号量集中的具体的信号量。这两个系统调用都使用了参数cmd,它用来指出要操作的具体命令。两个系统调用中的最后一个参数也不一样。在系统调用msgctl中,最后一个参数是指向内核中使用的数据结构的指针。我们使用此数据结构来取得有关消息队列的一些信息,以及设置或者改变队列的存取权限和使用者。但在信号量中支持额外的可选的命令,这样就要求有一个更为复杂的数据结构。
系统调用semctl()的第一个参数是关键字值。第二个参数是信号量数目。
参数cmd中可以使用的命令如下:
·IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
·IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
·IPC_RMID将信号量集从内存中删除。
·GETALL用于读取信号量集中的所有信号量的值。
·GETNCNT返回正在等待资源的进程数目。
·GETPID返回最后一个执行semop操作的进程的PID。
·GETVAL返回信号量集中的一个单个的信号量的值。
·GETZCNT返回这在等待完全空闲的资源的进程数目。
·SETALL设置信号量集中的所有的信号量的值。
·SETVAL设置信号量集中的一个单独的信号量的值。
进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
销毁已退出的子进程
原型:pid_twaitpid(pid_t pid,int *status,int options)
参数:pid:
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。
option: WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去
返回值:
当正常返回的时候,waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
原型:intkill(pid_t pid, int sig);s
参数:
pid:可能选择有以下四种:
1.pid > 0 ,pid是信号欲送往的进程的标识。
2.pid = 0,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
3.pid = -1,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
4.pid < -1,信号将送往以-pid为组标识的进程。
sig:准备发送的信号代码,
其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行
返回值:
成功,返回0
失败,返回-1,
errno被设为以下的某个值 :
EINVAL:指定的信号码无效
EPERM;没有给任何目标进程发送信号的权限
ESRCH:目标进程或进程组不存在
原型:pid_tfork(void);
返回值:该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程I D
(1)一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待委托者的服务请求。当这种请求到达时,父进程调用f o r k,使子进程处理此请求。父进程则继续等待下一个服务请求。
(2)一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程在fork返回后立即调用exec.
原型:int execv(const char *path, char *const argv[]);
execv()用来执行参数path字符串所代表的文件路径,第二个参数利用数组指针来传递给执行文件。
返回值
如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码
原型:intexecve(const char *filename, char *const argv[],char *const envp[]);
参数:用来执行参数filename字符串所代表的文件路径,
第二个参数:系利用数组指针来传递给执行文件,
最后一个参数:传递给执行文件的新环境变量数组。
返回值
如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。
函数说明:最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n 的话,将不会溢出。
原型:intsnprintf(char *restrict buf, size_t n, const char * restrict format, ...);
返回值:若成功则返回欲写入的字符串长度,若出错则返回负值
intfprintf( FILE *stream, const char *format, ... );
fprintf()函数根据指定的format(格式)(格式)发送信息(参数)到由stream(流)指定的文件.fprintf()只能和printf()一样工作. fprintf()的返回值是输出的字符数,发生错误时返回一个负值.
原型:intsystem(const char * string);
函数说明:
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。在调用system()期间 SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值:
=-1:出现错误
=0:调用成功但是没有出现子进程
>0:成功退出的子进程的id
signal():
synopsis:
signal(intsig,sighandler_t handler);
description:
sig用于指定信号类型.handle是用于处理该信号的函数
handle还可以是:
SIG_IGN忽略这个信号.
SIG_DFL恢复对这个信号的默认处理.