1、概述編程
本文主要講述了 Posix 標準的經常使用線程 API 接口的使用,目前 Linux/Unix 均提供了遵循 Posix 標準的線程編程 API,微軟提供了本身的一套接口,acl 線程模塊庫根據 Posix 標準,提供了跨平臺(支持 LINUX/WIN32)的線程庫,接口定義及參數含義均與 Posix 的相同。若是您對 Linux 下的線程 API 比較熟悉,則當須要移植您的程序至 WIN32 平臺時,只要須要在所用線程 API 前加前綴 acl_,同時將 acl 的 lib_acl.a 及相應頭文件集成到您的程序中,便可將 LINUX 下線程程序移植至 WIN32 平臺。函數
2、經常使用API 介紹spa
1)建立線程 API:pthread_create,在 acl 庫中的表現形式:acl_pthread_create.net
/** * 建立獨立的線程,使處理任務在該線程中運行,線程運行完畢,該線程的建立者 * 能夠接收該線程的退出返回值 * @param tid {pthread_t*} 當線程建立成功時,該變量所指內存區域存儲線程 * 的線程 ID 號 * @param attr{pthread_attr_t*} 建立線程的屬性,該屬性裏能夠設定線程的 * 堆棧大小、是否與建立線程分離等 * @param start_routine {void *(*)(void*)} 線程成功建立後開始運行的函數指針, * 該函數指針是用戶應用的功能函數入口,函數的參數也由用戶指定 * @param arg {void*} start 函數運行時傳入的參數,該參數由用戶設定 * @return {int} 線程建立是否成功,返回 0 表示成功,不然表示失敗 * */ int pthread_create(pthread_t* tid, pthread_attr_t* attr, void *(*start)(void*), void *arg);
該 API 中有兩個參數類型:pthread_t 和 pthread_attr_t,其中的建立線程屬性的類型 pthread_attr_t 通常由下面 API 來初始化。線程
2)初始化/銷燬線程屬性 API:pthread_attr_init/pthread_attr_destroy,在 acl 庫中的對應形式:acl_pthread_attr_init/acl_pthread_attr_destroy指針
/** * 初始化建立線程時的屬性對象,該 API 會賦一些缺省值給屬性對象,用戶若想 * 改變屬性中的某個缺省值,能夠經過 pthread_attr_setxxx 之類的 API 設定 * @param attr {pthread_attr_t*} 線程屬性對象的指針,該指針指向的空間 * 必須由用戶本身分配 * @return {int} 成功則返回 0,不然返回非 0 值 */ int pthread_attr_init(pthread_attr_t *attr); /** * 銷燬由 pthread_attr_init 建立的一些線程屬性資源 * @param attr {pthread_attr_t*} 線程屬性對象指針 * @return {int} 成功則返回 0,不然返回非 0 值 */ int pthread_attr_destroy(pthread_attr_t *attr);
在調用 pthread_attr_init 時,內部會對線程屬性對象建立一些臨時內存資源,因此當不須要線程屬性時,須要調用 pthread_attr_destroy 來釋放之。code
下面的兩個 API 能夠設定建立時的一些特殊屬性:對象
3)設定建立線程爲分離狀態:int pthread_attr_setdetachstate(pthread_attr_t *attr, int detached),在 acl 庫中的表現形式:int acl_pthread_attr_setdetachstate(acl_pthread_attr_t *attr, int detached);blog
/** * 設定所建立線程是否處於分離模式,當父線程建立一個子線程時指定了所建立 * 子線程爲可分離模式,則父線程沒必要接管子線程的退出狀態,不然父線程必須 * 調用 pthread_join 來接管子線程的退出狀態以免資源泄露 * @param attr {pthread_attr_t*} 線程屬性對象 * @param detached {int} 非 0 表示採用線程分離模式 * @return {int} 返回 0 表示成功,不然表示出錯 */ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detached);
4)設定線程建立時線程堆棧大小屬性:int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize),在 acl 庫中的表現形式:int acl_pthread_attr_setstacksize(acl_pthread_attr_t *attr, size_t stacksize)。接口
/** * 該函數設定所建立線程的堆棧大小 * @param attr {pthread_attr_t*} 線程屬性對象 * @param stacksize {size_t} 新建立線程的堆棧大小(單位爲字節, * 在LINUX 下默認堆棧通常是 2MB) * @return {int} 返回 0 表示成功 */ int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
5)當建立的子線程爲非分離狀態時父線程接管子線程退出狀態:int pthread_join(pthread_t thread, void **thread_return) ,在 acl 庫中的表現形式爲:int acl_pthread_join(acl_pthread_t thread, void **thread_return)。
/** * 當所建立的子線程採用非分離方式建立時,則父線程應該調用本 API * 來接管子線程的退出狀態,不然會形成資源泄露 * @param thread {pthread_t} 子線程的線程號 * @param thread_return {void**} 該指針地址指向子線程退出 * 前返回的內存地址 * @return {int} 返回 0 表示成功,不然表示失敗 */ int pthread_join(pthread_t thread, void **thread_return);
在建立線程前經過 pthread_attr_setdetachstate API 給線程屬性設定了將要建立的子線程爲分離狀態,還有另一個 API 能夠當子線程建立後再指定子線程爲分離狀態:
6)子線程建立成功後設定子線程的分離狀態:int pthread_detach(pthread_t thread),在 acl 庫中的表現形式爲:int acl_pthread_detach(acl_pthread_t thread)。
/** * 子線程建立成功後調用本函數設定子線程爲分離模式,調用本函數後, * 父線程禁止再調用 pthread_join 接管子線程的退出狀態 * @param thread {pthread_t} 所建立的子線程的線程號 * @return {int} 返回 0 表示成功,不然表示失敗 */ int pthread_detach(pthread_t thread);
7)線程中得到自身的線程 ID 號:pthread_t pthread_self(void),在 acl 庫中的表現形式爲:unsinged long acl_pthread_self(void)。
/** * 返回當前線程的線程號 * @return {pthread_t} */ pthread_t pthread_self(void);
以上介紹了有關 Posix 標準線程的一些經常使用 API,下面舉一個簡單的例子來講明上面 API 的使用。
3、例子
#include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> static void *mythread_main(void *arg) { char *ptr = (char*) arg; printf("my thread id: %ld\r\n", pthread_self()); printf("arg: %s\r\n", ptr); free(ptr); /* 釋放在父線程中分配的內存 */ ptr = strdup("thread exit ok"); return ptr; } int main(void) { char *name = strdup("thread_test"); pthread_t tid; pthread_attr_t attr; /* 初始化線程屬性對象 */ if (pthread_attr_init(&attr) != 0) { /* 此處出錯應該是內存資源不夠所至 */ printf("pthread_attr_init error: %s\r\n", strerror(errno)); return 1; } /* 設定子線程的堆棧空間爲 4MB */ if (pthread_attr_setstacksize(&attr, 4096000) != 0) { printf("pthread_attr_setstacksize error: %s\r\n", strerror(errno)); pthread_attr_destroy(&attr); /* 必須釋放線程屬性資源 */ return 1; } /* 建立子線程 */ if (pthread_create(&tid, mythread_main, name) != 0) { printf("pthread_create error: %s\r\n", strerror(errno)); pthread_attr_destroy(&attr); /* 必須釋放線程屬性資源 */ return 1; } printf("ok, create thread id: %ld\r\n", tid); /* 接管子線程的退出狀態 */ if (pthread_join(&tid, &ptr) != 0) { printf("pthread_join error: %s\r\n", strerror(errno)); pthread_attr_destroy(&attr); /* 必須釋放線程屬性資源 */ return 1; } printf("child thread exit: %s\r\n", ptr); free(ptr); /* 釋放在子線程分配的內存 */ pthread_attr_destroy(&attr); /* 釋放線程屬性資源 */ return 0; }
上述例子中,只需把 pthread_ 前添加前綴 acl_,同時包含頭文件 #include "lib_acl.h",該例子即可以在 WIN32 平臺下運行了。
本節暫且說這一些有關線程編程時用到的 API,下一節繼續。