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;
}