Linux多線程實踐(2),linux多線程實踐
POSIX線程庫
與線程有關的函數構成了一個完整的系列,絕大多數函數的名字都是以“pthread_”打頭,要使用這些函數庫,要通過引入頭文<pthread.h>,而且連結這些線程函數庫時要使用編譯器命令的“-lpthread”選項[Ubuntu系列系統需要添加的是”-pthread”選項而不是”-lpthread”,如Ubuntu 14.04版本,深度Ubuntu等]
pthread_create
建立一個新的線程
int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);
參數:
thread:線程ID
attr:設定線程的屬性,attr為NULL表示使用預設屬性
start_routine:是個函數地址,線程啟動後要執行的函數
arg:傳給線程啟動函數的參數
傳回值:成功返回0;失敗返回錯誤碼
附-錯誤檢查
UNIX傳統的函數:成功返回0,失敗返回-1,並且對設定全域變數errno以指定錯誤類型。然而pthreads函數出錯時不會設定全域變數errno(而其他的大部分POSIX函數會設定errno)。而是將錯誤碼通過傳回值返回;
pthreads同樣也提供了線程內的errno變數,以支援其它使用errno的代碼。對於pthreads函數的錯誤,建議通過傳回值進行判定,因為讀取傳回值要比讀取線程內的errno變數的開銷更小!
//實踐#include <iostream>#include <errno.h>#include <unistd.h>#include <pthread.h>#include <string.h>#include <stdio.h>#include <stdlib.h>using namespace std;void *thread_routine(void *args){ for (int i = 0; i < 20; ++i) { printf("A"); fflush(stdout); usleep(20); } return 0;}int main(){ pthread_t tid; int ret = 0; if ((ret = pthread_create(&tid,NULL, thread_routine,NULL),NULL) != 0) { fprintf(stderr,"%s\n",strerror(ret)); exit(-1); } for (int i = 0; i < 20; ++i) { printf("B"); fflush(stdout); usleep(20); } cout << endl; pthread_join(tid,NULL);//該函數下面會遇到:等待線程結束}
運行結果(可以發現線程是交替啟動並執行,並且運行情況不一):
pthread_exit
線程終止
void pthread_exit(void *value_ptr);
參數:
value_ptr:指向該線程的傳回值;注意:value_ptr不能指向一個局部變數。
pthread_join
等待線程結束
int pthread_join(pthread_t thread, void **value_ptr);
參數:
thread:線程ID
value_ptr:它指向一個指標,後者指向線程的傳回值(使用者擷取線程的傳回值)
傳回值:成功返回0;失敗返回錯誤碼
//實踐void *threadFunction(void *args){ cout << "Start Thread..." << endl; cout << "End Thread..." << endl; pthread_exit(NULL);}int main(){ pthread_t thread; //啟動建立並啟動線程 pthread_create(&thread,NULL,threadFunction,NULL); cout << "Main Running..." << endl; cout << "Main Ending..." << endl; //等待線程結束 pthread_join(thread,NULL); return 0;}
pthread_self
返回線程ID
pthread_t pthread_self(void);DESCRIPTIONThe pthread_self() function shall return the thread ID of the calling thread.
//實踐1:void *thread_routine(void *args){ cout << pthread_self() << " START..." << endl; for (int i = 0; i < 20; ++i) { printf("A"); fflush(stdout); usleep(20); } sleep(3); cout << pthread_self() << " END..." << endl; pthread_exit(const_cast<char *>("thread_routine exit")); //return (void *)"EDF";}int main(){ pthread_t tid; int ret = 0; if ((ret = pthread_create(&tid,NULL, thread_routine,NULL),NULL) != 0) { fprintf(stderr,"pthread_create: %s\n",strerror(ret)); exit(EXIT_FAILURE); } for (int i = 0; i < 20; ++i) { printf("B"); fflush(stdout); usleep(20); } cout << endl; void *threadValue; if ((ret = pthread_join(tid,&threadValue)) != 0) { fprintf(stderr, "pthread_join: %s\n",strerror(ret)); exit(EXIT_FAILURE); } cout << "return message: " << static_cast<char *>(threadValue) << endl;}
//實踐2:主控線程與子線程傳遞資料typedef struct _Student{ char name[20]; unsigned int age;} Student;void *threadFunction(void *args){ cout << "In Thread: " << pthread_self() << endl; Student tmp = *(Student *)(args); cout << "Name: " << tmp.name << endl; cout << "Age: " << tmp.age << endl; pthread_exit(NULL);}int main(){ Student student = {"xiaofang",22}; pthread_t thread; //啟動建立並啟動線程 pthread_create(&thread,NULL,threadFunction,&student); //等待線程結束 pthread_join(thread,NULL); return 0;}
pthread_cancel
取消一個執行中的線程
int pthread_cancel(pthread_t thread);
傳回值:成功返回0;失敗返回錯誤碼;
pthread_detach
將一個線程分離-如果在新建立的線程結束時主線程沒有結束同時也沒有調用pthread_join,則會產生僵線程,次問題可以通過設定線程為分離的(detach)來解決;
int pthread_detach(pthread_t thread);
傳回值:成功返回0;失敗返回錯誤碼;
總結:進程 VS. 線程
進程(pid_t) |
線程(pthread_t) |
Fork |
Pthread_create |
Waitpit |
Pthread_join/Pthread_detach |
Kill |
Pthread_cancel |
Pid |
Pthead_self |
Exit/return |
Pthread_exit/return |