linux 下常用的建立多線程函數pthread_create(pthread_t * thread , pthread_attr_t * attr , void *(*start_routine)(void*) , void *args);其中第一個參數用來儲存線程資訊,第二個參數指新線程的運作屬性,可以設定為NULL,第三個參數為自定義的線程函數,第四個參數就是線程函數需要用到的參數,一般如果要傳遞多個參數,可以設定為結構體(struct)類型,這裡我們使用int類型的變量。 下面我着重讨論一個用for結構來建立多個線程時參數傳遞的問題
先看下面的例子,後面附有結果,先不要看,猜測一下會有什麼樣的輸出:
#include<iostream>
#include<pthread.h>
#include<semaphore.h>
using namespace std;
#define th_pop 20 //
pthread_mutex_t mutex;
pthread_t a_thread[th_pop];
void * thread_func(void *args)
{
pthread_mutex_lock(&mutex);
int t_id = *(int*)args;
cout<<"the id of this thread is "<<t_id<<endl;
pthread_mutex_unlock(&mutex);
return (void*)NULL;
}
void init()
{
pthread_mutex_init(&mutex, NULL);
for(int i=0; i<th_pop; i++)
{
pthread_create(&a_thread[i] , NULL , thread_func , &i);
}
//wait the end of the threads;
for(int i=0; i<th_pop; i++)
{
int res = pthread_join(a_thread[i] , NULL);
if(res != 0)
cout<<"the thread id: "<< i<<" ends fail"<<endl;
}
pthread_mutex_destroy(&mutex);
}
int main()
{
init();
return 0;
}
編譯運作
g++ -fpermissive args.cc -o args.o -pthread
./args.o
下面是輸出結果,由于線程執行的不确定性,可能你執行的時候得到的結果并非如此,這隻是一個代表而已
the id of this thread is 2
the id of this thread is 8
the id of this thread is 9
the id of this thread is 9
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
the id of this thread is 20
看到這個結果有沒有感覺到有什麼不對呢?可能你會感覺到很納悶,怎麼出現了那麼多的id=20的結果呢?其實這個認真分析一下并不難了解:
首先pthread_create函數傳遞的是一個指針型的參數,即傳遞的是一個位址而已,這樣在執行for結構時
for(int i=0; i<th_pop; i++)
{
pthread_create(&a_thread[i] , NULL , thread_func , &i);
}
該塊快速執行完成,并且将i置為20,故而傳遞的位址指向的内容為20,同時其它的線程還沒來得及執行 int t_id = *(int*)args;,這樣就使得多個線程都指向同一個位址,内容為20,解決該問題的一個辦法為中for結構中加入sleep(1),這樣當sleep時間大于線程函數執行時間,就可以得到一個正确的結果,不過這種辦法剝掉了并發性,并不可取,下面我們采用另一種方法。
我們隻修改init()函數
void init()
{
pthread_mutex_init(&mutex, NULL);
int thread_id[th_pop];
for(int i=0; i<th_pop; i++)
thread_id[i] = i;
for(int i=0; i<th_pop; i++)
{
int *t = thread_id +i;
pthread_create(&a_thread[i] , NULL , thread_func , (void*)t);
}
//wait the end of the threads;
for(int i=0; i<th_pop; i++)
{
int res = pthread_join(a_thread[i] , NULL);
if(res != 0)
cout<<"the thread id: "<< i<<" ends fail"<<endl;
}
pthread_mutex_destroy(&mutex);
}
下面輸出結果
the id of this thread is 0
the id of this thread is 4
the id of this thread is 2
the id of this thread is 5
the id of this thread is 1
the id of this thread is 3
the id of this thread is 6
the id of this thread is 7
the id of this thread is 8
the id of this thread is 9
the id of this thread is 10
the id of this thread is 11
the id of this thread is 12
the id of this thread is 13
the id of this thread is 14
the id of this thread is 15
the id of this thread is 16
the id of this thread is 17
the id of this thread is 18
the id of this thread is 19
從這個例子中我們應該明白,要避免直接在傳遞的參數中傳遞發生改變的量,否則會導緻結果不可測
http://hi.baidu.com/passionqiangli/blog/item/626ebe1ff8f103f5ae513319.html
===========================================================================
http://zhidao.baidu.com/question/315398992.html
涉及多參數傳遞給線程的,都需要使用結構體将參數封裝後,将結構體指針傳給線程
定義一個結構體
struct mypara
{
var para1;//參數1
var para2;//參數2
}
将這個結構體指針,作為void *形參的實際參數傳遞
struct mypara pstru;
pthread_create(&ntid, NULL, thr_fn,& (pstru));
函數中需要定義一個mypara類型的結構指針來引用這個參數
void *thr_fn(void *arg)
{
mypara *pstru;
pstru = (* struct mypara) arg;
pstru->para1;//參數1
pstru->para2;//參數2
}
pthread_create函數接受的參數隻有一個void *型的指針,這就意味着你隻能通過結構體封裝超過一個以上的參數作為一個整體傳遞。這是pthread_create函數的接口限定的,别人已經明确表明我隻接受一個參數,你硬要塞給他兩個肯定會出錯了。是以通過結構體這種組合結構變通一下,同樣實作了隻通過一個參數傳遞,但通過結構指針對結構資料成員的引用實作多參數的傳遞
這種用結構體封裝多參數的用法不僅僅用在pthread_create函數中,如果你自己設計的函數需要的參數很多〉=5個以上,都可以考慮使用結構體封裝,這樣對外你的接口很簡潔清晰,你的函數的消費者使用起來也很友善,隻需要對結構體各個成員指派即可,避免了參數很多時漏傳、誤傳(參數串位)的問題
結構體内包含結構體完全沒有問題,很多應用都這麼使用
舉例如下:
http://wenku.baidu.com/view/48a302ed6294dd88d0d26b73.html
- #include<stdio.h>
- #include<stdlib.h>
- #include<pthread.h>
- #include<errno.h>
- #include<unistd.h>
- typedef void* (*fun)(void*);
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- static pthread_cond_t recv_over = PTHREAD_COND_INITIALIZER;
- static pthread_cond_t decode_over = PTHREAD_COND_INITIALIZER;
- static pthread_cond_t play_over = PTHREAD_COND_INITIALIZER;
- void* receive(void*);
- void* decode(void*);
- void* play(void*);
- pthread_t tdec, tplay, trecv;
- struct mypara
- {
- int thread_id;
- char *thread_name;
- };
- int main(int argc, char** argv)
- {
- struct mypara para;
- para.thread_id = 1;
- para.thread_name = "recv";
- int t1 = 0, t2 = 0, t3 = 0;
- t1 = pthread_create(&trecv, NULL, receive,& (para));
- if(t1 != 0)
- printf("Create thread receive error!\n");
- t2 = pthread_create(&tdec, NULL, decode, NULL);
- if(t2 != 0)
- printf("Create thread decode error!\n");
- t3 = pthread_create(&tplay, NULL, play, NULL);
- if(t3 != 0)
- printf("Create thread play error!\n");
- pthread_join(trecv, NULL);
- pthread_join(tdec, NULL);
- pthread_join(tplay, NULL);
- printf("leave main\n");
- exit(0);
- }
- void* receive(void* arg)
- {
- printf("Start receive\n");
- int i = 0;
- char *s = NULL;
- struct mypara *recv_para;
- recv_para = (struct mypara *)arg;
- i = (*recv_para).thread_id;
- s = (*recv_para).thread_name;
- printf("NO : %d Name : %s\n",i,s);
- sleep(2);
- pthread_mutex_lock(&mutex);
- while (1)
- {
- printf("Receiving...\n");
- sleep(1);
- pthread_cond_signal(&recv_over);
- pthread_cond_wait(&decode_over, &mutex);
- }
- printf("End receive\n");
- pthread_exit(0);
- }
- void* decode(void* arg)
- {
- printf("Start decode\n");
- while (1)
- {
- pthread_cond_wait(&recv_over, &mutex);
- printf("Decoding...\n");
- sleep(1);
- pthread_cond_broadcast(&decode_over); //inform player ready to play
- }
- printf("End decode\n");
- pthread_exit(0);
- }
- void* play(void* arg)
- {
- int ret;
- printf("Start play\n");
- while(1)
- {
- pthread_cond_wait(&decode_over, &mutex); //wait the signal from decoder
- printf("Playing...\n");
- sleep(1);
- }
- pthread_mutex_unlock(&mutex);
- printf("End play\n");
- pthread_exit(0);
- }