pthread_create()是Linux中創建線程的一種方式。
#include<pthread.h> int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*) ,void *arg); //第一個參數為指向線程標識符的指針。 //第二個參數用來設置線程屬性。 //第三個參數是線程運行函數的起始地址。 //第四個參數是運行函數的參數。 //pthread_create() 在調用成功完成之后返回零。其他任何返回值都表示出現了錯誤。
用到多線程,就用for語句循環創建多個線程,但是出現了一些問題,特此記錄下。
原代碼:
pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); for(int a=0;a<num_threads;a++) pthread_create(&pt[a],NULL,function,&a); for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL);
創建線程時是需要把a傳入函數function中的,但是,這樣會出現混亂,比如,我們需要往第0個線程傳入參數0,實際上運行結果顯示傳入第0個線程的參數不是0。
網上查詢資料之后,大概問題就是,CPU運行速度很快,而pthread_create()創建線程要有一定的時間,在pthread_create()創建線程再去按照之前參數a的地址去取a時,循環中a的值已經發生了變化,這就造成傳入函數function的參數值不對。
既然這樣,就讓主線程循環時等一下pthread_create(),於是代碼變成下面這樣:
pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t));
for(int a=0;a<num_threads;a++)
{
pthread_create(&pt[a],NULL,function,&a);
sleep(1); //#include<unistd.h>
}
for(int a=0;a<num_threads;a++) {
pthread_join(pt[a],NULL);
}
循環時主線程掛起1秒鍾,pthread_create()就創建線程完畢了,但這樣帶來的問題就是:我們使用多線程的初衷就是並行運算、提升效率,但每創建一個線程就能停1秒,如果我們創建線程的次數比較多,那將大大影響程序的整體運行效率。試了一下,如果將sleep(1)改成usleep(1000),即睡眠1000微秒(1毫秒),仍可能出現錯誤。
通過網上資料,經過實踐,發現以下兩種方法可以解決:
1、實現開辟一塊空間存儲創建多線程時所需要傳入的參數,這樣每個線程的參數的地址就不會亂套。
2、在循環創建線程時,我們不直接把循環的控制變量(如上例中的a)直接傳入多線程的函數中,我們另外申請一塊空間,存儲在這塊空間上,到時再從這塊空間取值就行了。
種方法的解決方法如下:
//第一種方法 pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); int order[num_threads]; for(int a=0;a<num_threads;a++) order[a]=a; for(int a=0;a<num_threads;a++) pthread_create(&pt[a],NULL,function,&order[a]); for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL); //第二種方法 pthread_t *pt=(pthread_t*)malloc(num_threads*sizeof(pthread_t)); for(int a=0;a<num_threads;a++) { int* temp=(int*)malloc(sizeof(int)); *temp=a; pthread_create(&pt[a],NULL,function,(void*)temp); } for(int a=0;a<num_threads;a++) pthread_join(pt[a],NULL);
兩種效果方法差不多,但是第二種方法使用malloc申請了動態內存,而且還沒有釋放,所以不是太好。