問題產生:
進程之間切換需求資源大,時間長,尋找一種更好的方法,出現線程。
新進程和新線程的區別:新進程擁有自己PID、變數、時間獨立、執行獨立。新線程擁有自己棧(即擁有自己的局部變數)、但它與建立者共用PID、全域變數、訊號處理函數、目前的目錄狀態等。 線程過程:
必須定義宏_REENTRANT並且依賴於pthread.h標頭檔,編譯時間使用-lpthread選項。 線程屬性:
最重要的兩個是:
#include <pthread.h>int pthreed_attr_init(pthread_attr_t *attr);int pthread_attr_destroy(pthread_attr_t*attr);
還有其他的一些,自己百度,通過各種線程屬性函數可設定如脫離狀態、線程調度等。
程式碼範例:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>void *thread_function(void *arg);char message[] = "Hello World";int thread_finished = 0;int main() { int res; pthread_t a_thread; void *thread_result; pthread_attr_t thread_attr; res = pthread_attr_init(&thread_attr);//屬性初始化 if (res != 0) { perror("Attribute creation failed"); exit(EXIT_FAILURE); } res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);//允許無需對線程重新合并 if (res != 0) { perror("Setting detached attribute failed"); exit(EXIT_FAILURE); }//建立線程 res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message); if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } (void)pthread_attr_destroy(&thread_attr);//屬性清理回收 while(!thread_finished) { printf("Waiting for thread to say it's finished...\n"); sleep(1); } printf("Other thread finished, bye!\n"); exit(EXIT_SUCCESS);}//線程函數void *thread_function(void *arg) { printf("thread_function is running. Argument was %s\n", (char *)arg); sleep(4); printf("Second thread setting finished flag, and exiting now\n"); thread_finished = 1; pthread_exit(NULL);}
線程過程 建立線程:
#include <pthread.h>int pthread_creat(pthread_t*thread,pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
參數1:線程被建立時,該指標指向的變數中將被寫入一個標識符以來引用新線程。
參數2:用於設定線程屬性。如不需要特殊屬性可設定NULL。
參數3:傳遞線程函數本體。
參數4:傳遞線程函數參數。
傳回值:成功返回0,錯誤返回錯誤碼。
看一下線程函數:void*thread_function(void *arg);//注意這裡的void * 等待線程:
#include <pthread.h>int pthread_join(pthread-t th,void **thread_return);
參數1:要等待的線程,為pthread_creat第一個參數的返回標識符。
參數2:一個二級指標,最終指向某線程的傳回值。
傳回值:成功返回0,錯誤返回錯誤碼。
注意:程式中如果沒有此函數,主程式就會很快結束而導致線程沒有時間開始就結束。該函數本質上是以阻塞式等待thread指定的線程結束以最後回收線程資源。區別於該函數的是另一種線程----脫離線程。
對於一個二級指標可以這樣使用:
void *thread_result;res = pthread_join(a_thread,&thread_result);
終止線程:
#include <pthread.h>void pthread_exit(void *retval);
取消線程:
#include <pthread.h>int pthread_cancle(pthread_t thread);//很簡單,不再多說int pthread_setcanclestate(int stat,int*oldstat);
參數1:取值可以是PTHREAD_CANCLE_ENABLE,該值允許線程接收取消請求。取值還可以是PTHREAD_CANCLE_DISABLE,作用是忽略取消請求。
參數2:用於擷取先前的取消狀態,如果不想用可設定為NULL。
int pthread_setcancletype(int type,int*oldtype);
參數1:取值可以是PTHREAD_CANCLE_ASYNCHRONOUS,作用是接收到取消請求後立即執行,還可以是PTHREAD_CANCLE_DEFEREED,作用是不立即執行,直到執行到下列函數後才採取行動:pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancle、sem_wait或sigwait。
參數2:用於擷取先前的取消狀態,如果不想用可設定為NULL。預設情況下,線程在啟動時的取消狀態為PTHREAD_CANCLE_ENABLE,取消類型為PTHREAD_CANCLE_DEFREED。 程式碼範例:
1、 不帶取消線程的代碼:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <pthread.h>void *thread_function(void *arg);char message[] = "Hello World";int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, (void *)message);//建立線程 if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } printf("Waiting for thread to finish...\n"); res = pthread_join(a_thread, &thread_result);//等待線程 if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); } printf("Thread joined, it returned %s\n", (char *)thread_result); printf("Message is now %s\n", message); exit(EXIT_SUCCESS);}void *thread_function(void *arg) { printf("thread_function is running. Argument was %s\n", (char *)arg); sleep(3); strcpy(message, "Bye!"); pthread_exit("Thank you for the CPU time");//退出線程}
2、 帶取消線程的代碼:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>void *thread_function(void *arg);int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_create(&a_thread, NULL, thread_function, NULL);//建立線程 if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } sleep(3); printf("Canceling thread...\n"); res = pthread_cancel(a_thread);//取消線程的實施 if (res != 0) { perror("Thread cancelation failed"); exit(EXIT_FAILURE); } printf("Waiting for thread to finish...\n"); res = pthread_join(a_thread, &thread_result);//等待線程 if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS);}//線程函數void *thread_function(void *arg) { int i, res, j; res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);//設定取消屬性狀態 if (res != 0) { perror("Thread pthread_setcancelstate failed"); exit(EXIT_FAILURE); } res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);//設定取消屬性類型 if (res != 0) { perror("Thread pthread_setcanceltype failed"); exit(EXIT_FAILURE); } printf("thread_function is running\n"); for(i = 0; i < 10; i++) { printf("Thread is still running (%d)...\n", i); sleep(1); } pthread_exit(0);//退出線程}
線程同步:
訊號量
類似於唯一門口檢查員
#include <semaphore.h>//初始化訊號量int sem_init(sem_t *sem,intpshared,unsigned int value);//控制訊號量int sem_wait(sem_t * sem);//類似於P原子操作,-1int sem_post(sem_t * sem);//類似於V原子操作,+1//清理訊號量int sem_destroy(sem_t * sem);
sem_init()函數參數解釋:
參數1:指向的訊號量指標。
參數2:控制訊號量類型,值為0時表示該訊號量是當前進程的局部訊號量,否則這個訊號量就可以在多個進程之間共用。
所有函數成功返回0。
程式碼範例:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <pthread.h>#include <semaphore.h>void *thread_function(void *arg);sem_t bin_sem;#define WORK_SIZE 1024char work_area[WORK_SIZE];int main() { int res; pthread_t a_thread; void *thread_result; res = sem_init(&bin_sem, 0, 0); if (res != 0) { perror("Semaphore initialization failed"); exit(EXIT_FAILURE); } res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } printf("Input some text. Enter 'end' to finish\n"); while(strncmp("end", work_area, 3) != 0) { fgets(work_area, WORK_SIZE, stdin); sem_post(&bin_sem); } printf("\nWaiting for thread to finish...\n"); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); } printf("Thread joined\n"); sem_destroy(&bin_sem); exit(EXIT_SUCCESS);}void *thread_function(void *arg) { sem_wait(&bin_sem); while(strncmp("end", work_area, 3) != 0) { printf("You input %d characters\n", strlen(work_area) -1); sem_wait(&bin_sem); } pthread_exit(NULL);}
互斥量
類似於唯一門口保安員
#include <pthread.h>//初始化訊號量int pthread_mutex_init(pthread_mutex_t*mutex,const pthread_mutexattr_t *mutexattr);//鎖住資源int pthread_mutex_lock(pthread_mutex_t*mutex);//解鎖資源int pthread_mutex_unlock(pthread_mutex_t*mutex);//清理訊號量int pthread_mutex_destroy(pthread_mutex_t*mutex);
pthread_mutex_init()函數參數解釋:
參數1:指向的訊號量指標。
參數2:這裡略掉,自己百度。
所有函數成功返回0,失敗返回錯誤碼,但是這些函數並不設定error。
程式碼範例:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <pthread.h>#include <semaphore.h>void *thread_function(void *arg);pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */#define WORK_SIZE 1024char work_area[WORK_SIZE];int time_to_exit = 0;int main() { int res; pthread_t a_thread; void *thread_result; res = pthread_mutex_init(&work_mutex, NULL); if (res != 0) { perror("Mutex initialization failed"); exit(EXIT_FAILURE); } res = pthread_create(&a_thread, NULL, thread_function, NULL); if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } pthread_mutex_lock(&work_mutex); printf("Input some text. Enter 'end' to finish\n"); while(!time_to_exit) { fgets(work_area, WORK_SIZE, stdin); pthread_mutex_unlock(&work_mutex); while(1) { pthread_mutex_lock(&work_mutex); if (work_area[0] != '\0') { pthread_mutex_unlock(&work_mutex); sleep(1); } else { break; } } } pthread_mutex_unlock(&work_mutex); printf("\nWaiting for thread to finish...\n"); res = pthread_join(a_thread, &thread_result); if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); } printf("Thread joined\n"); pthread_mutex_destroy(&work_mutex); exit(EXIT_SUCCESS);}void *thread_function(void *arg) { sleep(1); pthread_mutex_lock(&work_mutex); while(strncmp("end", work_area, 3) != 0) { printf("You input %d characters\n", strlen(work_area) -1); work_area[0] = '\0'; pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); while (work_area[0] == '\0' ) { pthread_mutex_unlock(&work_mutex); sleep(1); pthread_mutex_lock(&work_mutex); } } time_to_exit = 1; work_area[0] = '\0'; pthread_mutex_unlock(&work_mutex); pthread_exit(0);}
問題解決:多線程程式碼範例:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <pthread.h>#define NUM_THREADS 6void *thread_function(void *arg);int main() { int res; pthread_t a_thread[NUM_THREADS]; void *thread_result; int lots_of_threads; for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) { res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)lots_of_threads); if (res != 0) { perror("Thread creation failed"); exit(EXIT_FAILURE); } /* sleep(1); */ } printf("Waiting for threads to finish...\n"); for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) { res = pthread_join(a_thread[lots_of_threads], &thread_result); if (res == 0) { printf("Picked up a thread\n"); } else { perror("pthread_join failed"); } } printf("All done\n"); exit(EXIT_SUCCESS);}void *thread_function(void *arg) { int my_number = (int)arg; int rand_num; printf("thread_function is running. Argument was %d\n", my_number); rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0)); sleep(rand_num); printf("Bye from %d\n", my_number); pthread_exit(NULL);}
參考文檔:
Linux程式設計第四版 人民郵電出版社