clone函数调用
#include <sched.h>
int clone(int (*fn)(void *fnarg), void *child_stack, int flags, void *arg, ...
/* pid_t *pid, struct user_desc *tls, pid_t *ctid */ );
int __clone2(int (*fn)(void *), void *child_stack_base,size_t stack_size, int flags, void *arg, ...
/* pid_t *pid, struct user_desc *tls, pid_t *ctid */ );
指向子进程执行时调用的函数,fnarg是传给该函数的参数,child_stack是你为子进程分配的堆栈指针,flags通过将下表中的值相或得到,arg被传送给子函数,他的取值和用法完全有你决定,因为他为函数提供了上下文,用他从父进程向任何子进程传送数据,clone返回创建进程的进程ID,出错的话返回-1,设置errno,并不建立子进程。
CLONE_VM 若设置,父子进程运行在同一段内存
CLONE_FS 若设置,父子进程共享在root文件系统,当前工作目录以及umask信息
CLONE_FILES 若设置,父子信息共享文件描述服
CLONE_SIGHAND 若设置,父子进程共享在父进程上的信号处理器
CLONE_PID 若设置,父子进程具有相同的PID
pthread接口
一,建立一个新的线程
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
thread用来保存新线程的标识符,attr决定了对线程应用哪种线程属性,start_routine指向线程要执行的函数的指针,arg他是传递给前面的函数的参数,如果他有意义,则由用户来定义。pthread_create()执行成功返回0,并在thread中保存线程的标识符,失败则返回一个非零的退出码。
二,结束一个线程
#include <pthread.h>
void pthread_exit(void *value_ptr);
pthread_exit()函数用来终止当前的线程,并返回valure_ptr,该值可由父线程或其他线程通过pthread_join来检索。一个线程也可以简单的从其初始化函数的返回来终止。
三,等待一个线程结束
#include <pthread.h>
int pthread_join(pthread_t thread, void **value_ptr);
函数pthread_join()用来挂起当前的线程,直到thread指定的线程运行结束为止。thread用来指定线程,value_ptr为用户定义的一个指针,他可以用来存储等待进程的返回值。其他线程不能对同一线程再应用pthread_join函数。
四,登记函数
#include <pthread.h>
int pthread_atfork( void (*prepare)(void), /*在创建新线程之前调用*/
void (*parent)(void), /*在父线程中随后调用*/
void (*child)(void)); /*建立好子线程后立即在子线程中调用*/
pthread_atfork()函数登记三个函数,用来在某个时间来调用。他们都可以为NULL,此时,对应的函数将不发生调用。可以通过多次调用pthread_atfork函数登记多组处理函数。如果执行成功返回0,否则返回出错代码。注意,在即将出台的POSIX线程标准中,将不再包含pthread_atfork的调用。
五,取消线程
#include <pthread.h>
int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
void pthread_testcancel(void);
pthread_cancel用来取消thread指定的线程,pthread_setcancelstate用来设置他的取消状态,state是新状态,oldstate用来保存旧的状态,他可以是NULL,state的值可以是:
PTHREAD_CANCEL_ENABLE 允许请求取消
PTHREAD_CANCEL_DISABLE 忽略取消请求
pthread_setcanceltype用来改变一个线程对取消请求的响应方式,type的取值可以是:
PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
PTHREAD_CANCEL_DEFERRED 延迟取消直至下一个取消点,取消点用pthread_setcancel来建立,如果有任何正被挂起的取消请求,这个函数就会取消当前的线程,还类函数中,如果成功返回0,否则返回出错代码。
六,线程结束处理
#include <pthread.h>
void pthread_cleanup_pop(int execute);
void pthread_cleanup_push(void (*routine)(void*), void *arg);
当在线程中调用pthread_exit或者线程允许取消请求,而又到达一个取消点时,就调用routine函数,并将arg作为参数。处理函数被压入一个栈中,所以,当使用pthread_cleanup_pop时,取消最近的一个压入的函数,如果execute不为0,表明栈中还有可用的处理函数,此时,也会被执行,POSIX标准要求,每一个入栈操作都要对应一个出栈操作。
七,线程挂起
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
函数pthread_cond_init()用来初始化一个cond_t类型的对象,Linux中会忽略第二个参数,大多数的Linux的pthread程序只是简单的把PTHREAD_COND_INITIALIZER复制给attr,函数pthread_cond_destory()是cond_t类型对象的析构器,检查有没有线程正在等待条件的情况。pthread_cond_signal用来重启一个并且唯一的一个正在等待条件的进程 ,pthread_cond_broatcase与pthread_cond_signal的区别是他会重启所有正在等待条件的线程。这两个函数中的cond参数表示条件。pthread_cond_wait用来解开mutex指出的一个互斥锁,然后等待变量cond上的信号,pthread_cond_timedwait函数的功能与此类似,但他只等待abstime指定的时间。上述所有的函数成功后返回0,而在出错时返回错误代码。
八,线程比较
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
这个函数用来比较线程ID t1,t2引用的是不是同一个线程,是则返回0,否则返回非0;
九,线程属性
线程的属性控制着一个线程在他整个生命周期的行为,
属性 值 含义
datachstatc PTHREAD_CREATE_JOINABLE 可切入的状态
PTHREAD_CREATE_DETACHED 被分离的状态
schedpolicy SCHED_OTHER 正常,非实时
SCHED_RR 实时,循环
SCHED_FIFO 实时,先入先出
schedparam 与策略有关
inheritsched PTHREAD_EXPLICIT_SCHED 由schedpolice和schedparam设置,从
PTHREAD_INHERIT_SCHED 父进程继承
scope PTHREAD_SCOPE_SYSTEM 一个线程一个系统时间片,线程共享系统
PTHREAD_SCOPE_PROCESS 时间片(Linux不支持)
下列函数控制者线程属性对象,注意,这些调用不能控制和线程直接相关联的属性,产生的属性对象通常要传递给pthread_create函数。
#include <pthread.h>
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_getdetachstate(const pthread_attr_t *attr,
int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr,
int *restrict policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,
struct sched_param *restrict param);
int pthread_attr_setschedparam(pthread_attr_t *restrict attr,
const struct sched_param *restrict param);
int pthread_attr_getinheritsched(const pthread_attr_t *restrict attr,
int *restrict inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr,
int inheritsched);
int pthread_attr_getscope(const pthread_attr_t *restrict attr,
int *restrict contentionscope);
int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
十,互斥
用来保护被多个线程共享的数据不会被同时修改。一个互斥锁只有两种状态,加锁与解锁,加锁的互斥不但不让其他线程访问,而且互斥也规上锁进程所有,任何进程都能访问解锁互斥,但他却不归任何线程所有。
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_init函数创建指针mutex指向的互斥,并且用mutexattr指定的属性初始化该互斥。
互斥属性
属性 描述 备注
PTHREAD_MUTEX_INITIALIZER 创建一个快速互斥 调用线程被阻塞直至拥有互斥的线程解锁为止
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 创建一个递归互斥 不阻塞调用进程,但返回一个出错代码EDEADLK
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 创建一个检错互斥 成功返回并增加调用线程上锁的次数,但必须拥有同样次数的解锁
除了使用mutex参数,还可以使用下面的初始化过程静态创建pthread_mutex_t变量。
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int i = 0;
int j = 0;
void test1(int * num);
void test2(int * num);
int main(void)
{
pthread_t pt1, pt2;
if (pthread_create(&pt1, NULL, (void *)test1, (void *)&i))
{
perror("Creat pthread test1 error\n");
exit(EXIT_FAILURE);
}
if (pthread_create(&pt2, NULL, (void *)test2, (void *)&j))
{
perror("Creat thread test2 error\n");
exit(EXIT_FAILURE);
}
pthread_join(pt1, NULL);
pthread_join(pt2, NULL);
printf("Total = %d\n",i + j);
return 0;
}
void test1(int * num)
{
int i = 0;
while (i++ < 5)
printf("In test1 : i = %d\n", (*num)++);
sleep(5);
while (0 < i--)
printf("In test1 -after sleep : i = %d\n",(*num)++);
}
void test2(int * num)
{
int i = 0;
while (i++ < 4)
printf("In test2 : j = %d\n", (*num)++);
sleep(8);
while (0 < i--)
printf("In test2 -after sleep : j = %d\n", (*num)++);
}
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void test1(char * str)
{
int i = 0;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
while (i < 5)
printf("%s : i = %d\n", str, i++);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
puts("Error!");
sleep(3);
while (0 < i)
printf("%s : i = %d\n", str, i--);
}
int main(void)
{
pthread_t thread1;
pthread_create(&thread1, NULL, (void *)test1, (void *)"thread 1");
pthread_cancel(thread1);
pthread_join(thread1, NULL);
puts("Back to main");
return 0;
}