用临时变量作为线程参数的问题。
#include <stdio.h>
#include <pthread.h>
#include <assert.h>void* start_routine(void* param)
{ char* str = (char*)param; printf("%s:%s/n", __func__, str); return NULL;}
pthread_t create_test_thread()
{ pthread_t id = 0; char str[] = "it is ok!"; pthread_create(&id, NULL, start_routine, str); return id;}
int main(int argc, char* argv[])
{ void* ret = NULL; pthread_t id = create_test_thread(); pthread_join(id, &ret); return 0;}
分析:由于新线程和当前线程是并发的,谁先谁后是无法预测的。可能create_test_thread 已经执行完了,str已经被释放了,新线程才拿到这参数,此时它的内容已经无法确定了,打印出的字符串自然是随机的。
o 线程参数共享的问题。
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
void* start_routine(void* param)
{ int index = *(int*)param; printf("%s:%d/n", __func__, index); return NULL;}
#define THREADS_NR 10void create_test_threads()
{ int i = 0; void* ret = NULL; pthread_t ids[THREADS_NR] = {0};
for(i = 0; i < THREADS_NR; i++)
{ pthread_create(ids + i, NULL, start_routine, &i); }
for(i = 0; i < THREADS_NR; i++)
{ pthread_join(ids[i], &ret); } return ;}
int main(int argc, char* argv[]){ create_test_threads(); return 0;}
分析:由于新线程和当前线程是并发的,谁先谁后是无法预测的。i在不断变化,所以新线程拿到的参数值是无法预知的,打印出的字符串自然也是随机的。
当我们需要在一个循环中传递参数时,使用使用函数的方法一般都是:
for(int I=0;I<100;I++){
fun(I); //使用函数传递i
}
每一个循环都会等待fun(I);函数执行完后再进行下一个循环。
但是当我们需要这个循环中创建线程,并将I的参数传递给线程时,如依然使用以上方法,会造成什么情况呢?
DWORD WINAPI ThreadFun(LPVOID lpParam){ //线程函数
Int *I = (int *)lpParam;
Return 0;
}
int I;
for(I=0;I<100;I++){
DWORD dwThreadId;
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadFunc,&I,0,&dwThreadId);
}
好了,到这里我们就可以发现,在循环中,我们创建线程并传递的参数是I=1后,主程序有可能在执到下一次循环时,第一次的ThreadFun函数仍未执行,而此时的I已经等2了,如果ThreadFun再来调用 Int *I = (int *)lpParam;语句时,显然不是我们想要的结果。
解决此问题的一种方法,便是可以使用静态数组来保存所要传递的参数。如下:
int I;
static int nPara[100]; //此句需定义为全局
for(I=0;I<100;I++){
DWORD dwThreadId;
HANDLE hThread;
NPara[I]=I; //保存参数
hThread = CreateThread(NULL,0,ThreadFunc,&nPara[I],0,&dwThreadId);
}
此时,所有参数均保存在nPara数组中,刚才的问题是解决了。
接下来又有了新的问题,让我们一起来看看吧:
1、如果需要创建的线程不止100,而是非常的大,而且我们也并不知道会有多少次循环的时侯。
2、如果我们需要传递的参数不单单只是一个int型的I,而是一个类。那么我们声明的时侯(假设线程数量最大为65535)则:
static CMYClass myClass[65535];
编译之后,得到的文件将会堆上一大堆的垃圾。相信任何一位程序都不想看到自己的程序上面堆了一堆垃圾在上面吧。
那么,还有没有更好的办法解决呢。答案是一定的,这里,我就讲一下我自己常用的方法:
动态创建对像传递参数。
一提到动态创建,我们自然会想到new 与 delete ,对了,我想说的也正是他们的使用。
假设参数类型为:
typedef struct _PARA{
int I;
DWORD dwNumber;
HWND hOther;
}Para;
使用new 在堆栈中申请一遍空间,在使用完后必需使用delete将其释放。
int I;
for(I=0;I<100;I++){
DWORD dwThreadId;
HANDLE hThread;
Para *myPara = new Para;
MyPara->I = I;
MyPara->dwNumber = 0 ;//自定
MyPara ->hOther = GetSafeHWnd();//当前窗体句柄
hThread = CreateThread(NULL,0,ThreadFunc,myPara,0,&dwThreadId);
}
//线程函数
DWORD WINAPI ThreadFun(LPVOID lpParam){ //线程函数
Para *myPara = (Para *)lpParam;
//执行其他功能
delete [] myPara; //释放
Return 0;
}
这样的话,也就不怕传递的参数多少与线程的数量太大了。另外如有需要的话可以加上一个线程计数器,保证当前线程的最大数量。
通常情况,我比较喜欢把线程处理放在一个类中处理,在主程序中尽量不与线程打交道。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/absurd/archive/2008/12/16/3527736.aspx