4.#include <string.h>
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
s1等于s2返回0,s1大于s2返回大于0的整数,s1小于s2返回小于0的整数
5.#include <stdlib.h>
int atoi(const char *nptr);将nptr指向的字符串转换成整数
long atol(const char *nptr);将nptr指向的字符串转换成长整数
long long atoll(const char *nptr);将nptr指向的字符串转换成长长整数
13.#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
这个系统调用指令是为进程制定而设计的,明确的选择取决于option。
14.#include <sys/types.h>
#include <unistd.h>
int setuid(uid_t uid);
Linux中, setuid(uid)函数的执行步骤为:(1)如果由普通用户调用,将当前进程的有效ID设置为uid. (2)如果由有效用户ID符为0的进程调用,则将真实,有效和已保存用户ID都设置为uid.函数在执行成功的时候返回0,在出错的时候返回-1.
15.#include <sys/capability.h>
int capget(cap_user_header_t hdrp, cap_user_data_t datap);
int capset(cap_user_header_t hdrp, const cap_user_data_r datap);
capget() 用来获得进程的权能;capset() 用来设置进程权能。函数在执行成功的时候返回0,在出错的时候返回-1。
16.#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
Compile and link with -pthread.
pthread_attr_init函数的作用初始化一个线程对象的属性,需要用pthread_attr_destroy函数对其去除初始化。
返回0,表示函数初始化对象成功。失败时返回一个非零错误代码。
17.#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
Compile and link with -pthread.
detachstate参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。
返回0,表示函数初始化对象成功。失败时返回一个非零错误代码。
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。所以如果我们在创建线程时就知道不需要了解线程的终止状态,则可以pthread_attr_t结构中的detachstate线程属性,让线程以分离状态启动。
设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。
18.#include <pthread.h>
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *param);
Compile and link with -pthread.
设置/获得线程的调度参数。若成功返回0,若失败返回非零错误代码。
struct sched_param
{
int sched_priority;
};
int sched_get_priority_max(int policy);
int sched_get_priority_min(int policy);
获得系统支持的线程优先权的最大和最小值。
19.#include <pthread.h>
int pthread_attr_setscope(pthread_attr_t *attr,int scope);
int pthread_attr_getscope(const pthread_attr_t *attr,int *scope);
Compile and link with -pthread.
设置/获得线程的作用域。若成功返回0,若失败返回非零错误代码。
20.#include <pthread.h>
int pthread_attr_getschedpolicy(const pthread_attr_t *attr,int *policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr,int policy);
Compile and link with -pthread.
获得/设置线程的调度策略。若成功返回0,若失败返回非零错误代码。
21.#include <pthread.h>
int pthread_attr_getstackaddr(const pthread_attr_t *attr,void **stackaddf);
int pthread_attr_setstackaddr(pthread_attr_t *attr,void *stackaddr);
Compile and link with -pthread.
获得/修改线程栈的位置。若成功返回0,若失败返回非零错误代码。
stacksize 属性定义系统分配的栈大小(以字节为单位)。size 不应小于系统定义的最小栈大小。
size 包含新线程使用的栈的字节数。如果 size 为零,则使用缺省大小。在大多数情况下,零值最适合。
PTHREAD_STACK_MIN 是启动线程所需的栈空间量。此栈空间没有考虑执行应用程序代码所需的线程例程要求。
#include <pthread.h>
void *child_thread(void *arg)
{
printf(“child thread run!\n”);
}
23.#include <pthread.h>
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t *guardsize);
Compile and link with -pthread.
获得/修改线程栈末尾的警戒缓冲区大小。若成功返回0,若失败返回非零错误代码。
线程属性guardsize控制着线程栈末尾之后以避免栈溢出的扩展内存大小,默认设置为PAGESIZE个字节。
可以把guardsize线程属性设为0,从而不允许属性的这种特征行为发生:在这种情况下不会提供警戒缓存区。同样地,如果对线程属性stackaddr(线程堆栈的地址)作了修改,系统就会假设我们会自己管理栈,并使警戒栈缓冲区机制无效,等同于把guardsize线程属性设为0。
如果guardsize大于零,则会为每个使用attr创建的线程提供大小至少为guardsize字节的溢出保护区。
24.#include <pthread.h>
int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr,size_t stacksize);
int pthread_attr_getstack(pthread_attr_t *attr,void **stackaddr,size_t *stacksize);
Compile and link with -pthread.
设置/获取堆栈地址和大小。若成功返回0,若失败返回非零错误代码。
25.#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
Compile and link with -pthread.
若线程创建成功,则返回0。若线程创建失败,则返回出错编号,并且*thread中的内容是未定义的。
与fork()调用创建一个进程的方法不同,pthread_create()创建的线程并不具备与主线程(即调用pthread_create()的线程)同样的执行序列,而是使其运行start_routine(arg)函数。thread返回创建的线程ID,而attr是创建线程时设置的线程属性。pthread_create()的返回值表示线程创建是否成功。尽管arg是void*类型的变量,但它同样可以作为任意类型的参数传给start_routine()函数;同时,start_routine()可以返回一个void*类型的返回值,而这个返回值也可以是其他类型,并由pthread_join()获取。
26.#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。若成功返回0,若失败返回非零错误代码。
其实在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone()。该系统调用copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。不过这个copy过程和fork不一样。 copy后的进程和原先的进程共享了所有的变量,运行环境。这样,原先进程中的变量变动在copy后的进程中便能体现出来。
27.#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); --- 无条件等待
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *tm); --- 计时等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。
条件变量的创建和注销
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; --- 静态创建
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); --- 动态创建
尽管POSIX标准中为条件变量定义了属性,但在Linux Threads中没有实现,因此cond_attr值通常为NULL,且被忽略。
int pthread_cond_destroy(pthread_cond_t *cond); --- 注销
只有在没有线程在该条件变量上等待的时候才能注销这个条件变量,否则返回EBUSY。因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程。
28.#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
29.#include <unistd.h>
int pipe(int pipefd[2]);
成功,返回0,否则返回-1。参数数组包含pipe使用的两个文件的描述符。fd[0]:读管道,fd[1]:写管道。
必须在fork()中调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
30.#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );