设为首页 加入收藏

TOP

windows多线程编程星球(一)(二)
2017-10-11 18:24:43 】 浏览:743
Tags:windows 线程 编程 星球
SECURITY_ATTRIBUTES, 线程的安全属性,可以写一个专门的主题,0表示默认值 16 * 1024L, //为线程分配的堆栈大小,会在最后特别提一下这个,在PC上没啥感觉,但是我在嵌入式上经常被坑 ThreadProc, //线程执行函数,也就是你具体需要这个线程干嘛 &Planet1, //主线程传给线程函数的参数(地址块) 0, //一些标志位,比如你可以创建一个线程不让他立即执行 NULL);//返回线程id,如果你需要,可以定义一个dword,在这个函数调用成功后会写入线程的id

     看到上面的函数,不得不自然说的是这个第三个参数,threadproc,这个参数的定义类型是”_In_      LPTHREAD_START_ROUTINE lpStartAddress”,_In_表示是一个输入值,中间这个LPTHREAD_START_ROUTINE是一个函数指针,定义如下:

typedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (
    [in] LPVOID lpThreadParameter
);

     这个看起来超级复杂的式子其实就是指向一个返回值是dword并且没有参数的函数的一个指针,本质上是一个地址,所以用lpStartAddress作为参数的名字。有了这个说明,所以ThreadProc的函数原型一定是这样的了:

DWORD WINAPI ThreadProc(
  _In_ LPVOID lpParameter
);

    在这个ThreadProc函数里面,目前只让子星球做两件事情,前进和旋转。而前进的动力来自于资源,但是你会发现貌似以目前介绍过的函数,你还没有办法控制这个资源和母星球资源之间的增减,所以我就先简单的假设子星球创建出来之后其资源是可以自己获取自己增加,这样他就可以不断的前进了。

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    struct Planet* p = (struct Planet*)lpParameter;
    int nSpinType = 0;

  
    while(true)
    {
        PlanetMove(*p);
        PlanetSpin(*p,500,nSpinType);
        nSpinType++;
    }
        
    return 1;
}


void PlanetMove(struct Planet &p)
{ 
    char cLine[100];
    memset(cLine,0,100*sizeof(char));


    if( p.resource < nMaxResource-1 ) 
    {
        p.resource++; 
        memset(cLine,'-',p.resource*sizeof(char)); 
        MoveOutputToPos(0,p.index*3+1,cLine,true); 
    } 
 }

       到这里,我们就可以补足PlanetSpin里面else的那一部分了,这一部分是为给子星球写的旋转代码。

else
 { 
        char sep = '*';
        
        MoveOutputToPos(0,p.index*3-1,&sep,false);  
        MoveOutputToPos(0,p.index*3,&sep,false);    
        

        MoveOutputToPos(p.resource,p.index*3+1,&spin[picType%4],false); 
        
        ::Sleep(spinInterval);
 }

       目前看来,我们已经可以自由的创建出一个星球,事实上,只要你愿意,你可以创建出多个。但是为了不要让问题搞的特别复杂,我还是先限定为一个。目前创建出来的星球一个最大的特点是不听使唤无法控制,你无法控制它前进与否,旋转与否,什么时候开始启动等等。因为一旦你仅仅是创建一个线程,你能对它做的很少很少。刚创建出来的线程就像一个熊孩子,无法控制,你得通过一些手段和方法来让它能够听从主线程的指挥或者和主线程互动。这也是后面慢慢要写的内容,也是多线程编程的核心内容了。

       【更多】这里我最想讨论的是CreateThread里面的第二个参数,以及线程id和线程handle的区别。 CreateThread的第二个参数表示给线程分配的起始堆栈大小,这个大小是耗用进程的虚拟内存空间的,在PC系统上一个进程的虚拟内存空间大小至少都是4G,所以大多数时候这个参数所造成的影响基本真的是没有。而我经常碰到的嵌入式平台,一个进程的虚拟内存地址有的时候非常的小,比如wince5只有32mb(虽然系统是老的不能再老了,但是还是有用),如果一旦不小心几个线程的这个参数值没有注意,很容易一起来就挂了。而一个线程除了起始堆栈大小,还有reserved堆栈大小,你可以理解为reserved的堆栈大小是一个用来保护作用的线程最大能够使用的堆栈大小,这个reserved的默认值一般是设置在exe的头部的,默认值一般是1MB。那么如果你第二个参数设置的大于1MB会怎么样呢,这样系统会默认增长reserved的内存大小到离起始大小最近的1MB。 特别注意的是如果在倒数第二个参数中使用STACK_SIZE_PARAM_IS_A_RESERVATION,那么你就可以设置这个reserved的堆栈大小,这个时候,起始堆栈大小就是exe程序头中的一个默认值。另外值得特别注意的是,线程的堆栈空间只有在线程自己退出的情况下才会被释放,如果这个线程是被其他线程终止的,那么这部分堆栈空间将不会被释放。忘了说了,终止线程的函数是TerminateThread,只需要一个线程的handle,和一个exit code作为参数就可以。说到handle和线程id的区别,简单的说可以认为handle是我们写程序所使用的线程标识符而id是一个用户可读的线程标识符。

 

三、不友好的显示。

         如果你使用上面的逻辑以及代码去运行一下这个程序,试图查看一下运行起来到底是什么样子的。我可以大胆预测你第一次运行看到的和你脑海里想的完全不一样,那你要说了,难道第二次就一样了吗?答案是还是不一样,第三次到第n次都和你想象的不一样并且很可能这n次相互之间也完全不一样。一种满屏的杂乱感,你会发现本有些该在指定位置输出的符号并没有输出,而是在另外一个风马牛不相及的地方输出了。调试一下吧,你会发现特别的不顺,甚至每一次运行结果行为都不一样。这就是多线程编程的一个特点和难点,难以调试并且预测,所以我们就需要对这种杂乱无章的行为进行约束和控制。

 &nb

首页 上一页 1 2 3 4 5 6 下一页 尾页 2/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇win7如何恢复以前的ie版本 下一篇在IE中解决当前安全设置不允许下..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目