[Mac-10.7.1 Lion Intel-based x64 gcc4.2.1]
Q: c標準中包含線程操作嗎?
A: 沒有。
Q: 給個mac下線程操作的例子吧。
A: 建立線程的函數可以實用pthread_create, 原型如下:
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表示線程執行的使用的參數。
範例程式碼(儲存為testForC.c):
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); } return NULL;}int main(){ pthread_t thread; int ret; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } return 0;}
運行:
可以看到,程式運行後然後很快就結束了,且沒有任何輸出。這是因為主線程過快結束導致結束了剛剛建立的子線程。
Q:如何讓主線程不理解結束呢?
A: 可以讓主線程進入等待狀態,加入while(1)迴圈讓主線程一直等待。
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); } return NULL;}int main(){ pthread_t thread; int ret; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } FOR_EVER(); return 0;}
運行結果:
上面是在子線程輸出字串的過程中截取的,子線程會一直運行下去,知道自己的迴圈退出。
Q: 子線程啟動並執行這麼快,讓它慢點行不?
A: 在子線程的while迴圈中加個延遲1秒的函數,如下:
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); sleep(1); // sleep for 1 second } return NULL;}int main(){ pthread_t thread; int ret; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } FOR_EVER(); return 0;}
運行結果:
從實際運行可以看出,子線程每列印一行會延遲一下。
Q: 主線程如何在規定的時間內幹掉子線程?
A: 主線程可以啟動定時器,在指定時間內幹掉子線程。
int setitimer(int which, const struct itimerval *restrict value, struct itimerval *restrict ovalue);
參數which表示定時器類型,value表示定時器時間資訊,ovalue可以設定為NULL.
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }pthread_t thread;int should_loop = 1;void kill_son_thread(int arg){ printf("now it will kill son thread...\n"); pthread_cancel(thread); should_loop = 0;}void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); sleep(1); // sleep for 1 second } return NULL;}int main(){ int ret; struct itimerval timer; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } // set the timer timer.it_value.tv_sec = 5; timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 5; timer.it_interval.tv_usec = 0; signal(SIGALRM, kill_son_thread); // register a signal for timer action setitimer(ITIMER_REAL, &timer, NULL); // start the timer while(should_loop) ; return 0;}
運行結果:
可以看到,主線程大約5秒後幹掉了子線程,然後結束了。
Q: pthread_exit不也可以退出線程嗎?
A: 是的。不用定時器,子線程5秒後自動結束,代碼如下:
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }pthread_t thread;int should_loop = 1;void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); sleep(1); // sleep for 1 second if(i == 6) { should_loop = 0; printf("[Son thread]: end...\n"); pthread_exit(NULL); } } return NULL;}int main(){ int ret; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } while(should_loop) ; printf("[Main thread]: end...\n"); return 0;}
運行結果:
Q: 還有個函數,pthread_join的作用是什嗎?
A: 它的作用是等待指定線程執行結束。它實現了線程之間的同步。
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }pthread_t thread;int should_loop = 1;void *thread_one_func(void *args){ int i = 1; while (i > 0) { printf("thread: loop %d\n", i++); sleep(1); // sleep for 1 second if(i == 6) { should_loop = 0; pthread_exit(NULL); } } return NULL;}int main(){ int ret; ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } pthread_join(thread, NULL); // wait for the son thread's end printf("[Son thread]: end...\n"); while(should_loop) ; printf("[Main thread]: end...\n"); return 0;}
運行結果:
Q: 上面的情形,主線程需要等待子線程結束,如果主線程不必等待子線程結束,子線程為主線程提供必要的資料,二者同步運行,如何處理?
A: 那麼,可以使用互斥體、訊號量等。
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }pthread_t thread;int should_loop = 1;pthread_mutex_t mutex;int data[3];void *thread_one_func(void *args){ int i = 1; while (i > 0) { pthread_mutex_lock(&mutex); data[0] = i; data[1] = i + 1; data[2] = i + 2; ++i; sleep(1); pthread_mutex_unlock(&mutex); } return NULL;}int main(){ int ret; // create and init a mutex pthread_mutex_init(&mutex, NULL); ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } while(1) { pthread_mutex_lock(&mutex); if(data[0] > 3) { pthread_mutex_unlock(&mutex); break; } printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]); pthread_mutex_unlock(&mutex); sleep(1); // avoid the main thread running too fast, thanks wufangna ! } pthread_mutex_destroy(&mutex); printf("[Main thread]: end...\n"); return 0;}
上面的代碼,主線程從全域資料data中讀取資料,子線程大約每1秒更新下data中的資料,當data[0]的值大於3的時候主線程退出。
運行結果:
Q: 還有種類型pthread_cond_t,它和pthread_mutex_t有什麼區別?
A: 前者是在某種情況下設定的"互斥體", 後者可以當成無條件的互斥體;例子如下,
#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define FOR_EVER() { while(1) ; }pthread_t thread;int should_loop = 1;pthread_mutex_t mutex;int data[3];pthread_cond_t cond;void *thread_one_func(void *args){ int i = 1; while (i > 0) { pthread_mutex_lock(&mutex); data[0] = i; data[1] = i + 1; data[2] = i + 2; if(data[0] % 2 == 0) pthread_cond_signal(&cond); ++i; sleep(1); pthread_mutex_unlock(&mutex); } return NULL;}int main(){ int ret; // create and init a mutex pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); ret = pthread_create(&thread, NULL, thread_one_func, NULL); if(ret != 0) { perror("pthread_create error"); return -1; } while(1) { pthread_mutex_lock(&mutex); if(data[0] > 6) { pthread_mutex_unlock(&mutex); break; } pthread_cond_wait(&cond, &mutex); printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]); pthread_mutex_unlock(&mutex); } pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); printf("[Main thread]: end...\n"); return 0;}
上面的代碼,主線程當發現data[0]大於6時就退出;小於6的時候,等待cond的狀態變化;子線程會更新data數組中的數值,且當data[0]是偶數的時候就啟用等待cond的線程(主線程),二者實現同步和互斥。
運行效果:
對於同步互斥,semaphore也可以實現; sem_open, sem_wait等等是操作它的函數,這裡不再一一介紹。
xichen
2012-5-19 15:46:26