先看一個例子:pthread1.c
- #if defined(WIN32)
- #include <windows.h> // void Sleep(DWORD ms)
- #define SLEEP(ms) Sleep(ms)
- #else if defined(LINUX)
- #include <unistd.h> // unsigned int sleep(unsigned int)
- #include <stdio.h>
- #include <stdlib.h>
- #define SLEEP(ms) sleep(ms)
- #endif
-
- #include <pthread.h>
-
- /** 作為線程入口的函數 */
- void * print_message_function(void *ptr)
- {
- SLEEP(5);
- char *message;
- message = (char *) ptr;
- printf("%s \n", message);
- return NULL;
- }
-
- int main(int argc, char* argv[])
- {
- pthread_t thread1, thread2;
- char *message1 = "Thread 1";
- char *message2 = "Thread 2";
- int iret1, iret2;
-
- // 成功創建線程時返回零
- iret1 = pthread_create(&thread1, NULL, &print_message_function, (void*) message1);
- iret2 = pthread_create(&thread2, NULL, &print_message_function, (void*) message2);
-
- /* 等待兩個線程結束 -- 同步
- * 如果不同步,則有可能主線程的return先執行,導致子線程未完成任務而先完蛋
- * 可以啟用Sleep試試。
- */
- pthread_join(thread1, NULL);
- pthread_join(thread2, NULL);
-
- printf("Thread 1 returns: %d\n", iret1);
- printf("Thread 2 returns: %d\n", iret2);
-
- return 0;
- }
* C compiler: cc -lpthread pthread1.c
* C++ compiler: g++ -lpthread pthread1.c
* pthread_exit
* 讓函數自己返回
* exit 停止整個進程(當然包括所有的線程)
- int pthread_create(pthread_t * thread,
- const pthread_attr_t * attr,
- void* (*start_routine)(void*),
- void *arg);
- pthread_create 的第二個參數pthread_attr_t
struct pthread_attr_t
{
enum 新線程是否與進程中其它線程脫離同步
{
PTHREAD_CREATE_JOINABLE [default] 可以在創建後用 pthread_detach 脫離同步
PTHREAD_CREATE_DETACHED 不能用 pthread_join 來同步,退出時自行釋放資源
} __detachstate;
enum 新線程的調用策略
{
SCHED_OTHER [default] 非實時
SCHED_RR 實時,輪轉法 - 僅對超級用戶有效
SCHED_FIFO 實時,先入先出 - 僅對超級用戶有效
} __schedpolicy;
struct sched_param 在運行時用 pthread_setschedparam 更新。
{
int sched_priority 線程的運行優先級。當上面的 __schedpolicy 為“實時”時才有效。缺省是零。
} __schedparam;
enum
{
PTHREAD_EXPLICIT_SCHED [default] 顯式指定調度策略和調度參數,即使用 attr 中的值
PTHREAD_INHERIT_SCHED 繼承調用者線程的值
} __inheritsched;
enum 線程間競���CPU的范圍
{
PTHREAD_SCOPE_SYSTEM [default] 目前Linux只實現了這一種
PTHREAD_SCOPE_PROCESS 僅與同進程的線程競爭
} __scope;
}
下面三個沒用過
* guard size
* stack address (See unistd.h and bits/posix_opt.h _POSIX_THREAD_ATTR_STACKADDR)
* stack size (default minimum PTHREAD_STACK_SIZE set in pthread.h)
- 創建線程時,如果寫成下面的樣子,也是可以的。這屬於精簡模式,作為函數指針的傳入參數是和上面等價的:
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
int pthread_join(pthread_t th, void **thread_return);
* th - 調用線程變為掛起狀態,等待線程退出。退出線程可用 pthread_exit() 或者 cancel 類線程函數。
* thread_return - 不置為NULL的話,可以傳出返回值。
void pthread_exit(void *retval);
若要在退出時返回數據在retval指向的內存裡,務必保證該內存不是在線程局部空間裡,否則會隨著線程退出而消失。
- 可以通過向某線程發送cancel請求而強制終止該線程。
該線程置自己為"cancel"狀態後,運行至取消點(cancelation point),才會退出。
POSIX標准規定的取消點:
- pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()
- read、write等會引起阻塞的系統調用
但pthread_cancel的手冊頁聲稱,由於LinuxThread庫與C庫結合得不好,因而目前C庫函數都不是取消點。
不過,cancel信號會使線程從阻塞的系統調用中退出,並置EINTR錯誤碼。所以可以把這樣的系統調用作為取消點:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
這樣,可達到POSIX的要求。
- int pthread_cancel (pthread_t th) 發送取消信號給線程。若成功返回零;失敗則非零。發送成功並不意味著線程會終止。
- int pthread_setcancelstate (int state, int *oldstate) 設置本線程對cancel信號的反應。
enum
{
PTHREAD_CANCEL_ENABLE [default] 收到信號後置自己為取消狀態
PTHREAD_CANCEL_DISABLE 忽略cancel信號,繼續運行
} state
- int pthread_setcanceltype (int type int *oldtype)
enum
{
PTHREAD_CANCEL_DEFERRED [default] 收到cancel信號後繼續運行,到達取消點時退出
PTHREAD_CANCEL_ASYNCHRONOUS 立即退出
} type 當上面的state為 PTHREAD_CANCEL_ENABLE 時該變量才有效。
- void pthread_testcancel (void)
檢查本線程是否處於取消狀態,若是,立刻退出。
- #ifdef WIN32
- #include <windows.h>
- #define SLEEP(ms) Sleep(ms)
- #else if defined(LINUX)
- #include <stdio.h>
- #define SLEEP(ms) sleep(ms)
- #endif
-
- #include <cassert>
- #include <pthread.h>
-
- static int s_nThreadResult = 0;
-
- void * theThread(void * param)
- {
- int count = 0;
- while (count < 20)
- {
- printf("[Child] looping\n");
- pthread_testcancel();
- SLEEP(1);
- count ++;
- }
-
- s_nThreadResult = 1;
- pthread_exit(&s_nThreadResult);
-
- return NULL;
- }
-
- int main(int argc, char * argv[])
- {
- int rc = 0;
- pthread_t tid;
- rc = pthread_create(&tid, NULL, &theThread, NULL);
- assert(rc == 0 && "pthread_create");
-
- SLEEP(3);
- // 若啟用下面代碼,則子線程提前返回
- //rc = pthread_cancel(tid);
- assert(rc == 0 && "pthread_cancel");
-
- // 阻塞自己,等待子線程返回
- void * status = NULL;
- rc = pthread_join(tid, &status);
- assert(rc == 0 && "pthread_join", rc);
-
- // 若子線程是被取消從而結束的,則無返回值
- if (status != PTHREAD_CANCELED && status != NULL)
- {
- printf("Returned value from thread: %d\n", *(int *)status);
- }
-
- return 0;
- }