现在的位置: 首页 > 综合 > 正文

Delphi Thread线程编程(4)

2014年01月06日 ⁄ 综合 ⁄ 共 2806字 ⁄ 字号 评论关闭

         核心提示:多线程是多任务操作系统下一个重要的组成部分,它能够提高应用程序的效率,然而,我们想利用好多线程,必须要了解很多的东西...

                                0. 前言

       多线程是多任务操作系统下一个重要的组成部分,它能够提高应用程序的效率,然而,我们想利用好多线程,必须要了解很多的东西,比如操作系统的原理,堆栈概念和使用方法。然而,使用不当,将会造成无尽的痛苦。

        在无数次的失败和查找资料解决问题之后,稍有感触,故写下此文,总结一下自己,同时,也给后学者一点启示,希望让他们少走弯路。

                             1.  基础知识。

       线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源

        一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。

      线程也有就绪、阻塞和运行三种基本状态

      线程的生死。

      在windows中,我们可以通过调用API  CreateThread/CreateRemoteThread创建一个线程(其实,在Windows内部,CreateThread最终是调用了CreateRemoteThread创建线程)

      当线程函数执行退出时,可以说这个线程已经完成了它的使命。调用ExitThread可以结束一个线程,同时调用CloseHandle来释放Windows分配给它的句柄资源。

     GetExitCodeThread可以用来检测线程是否已经退出

 

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,           
// SD,线程的属性  DWORD
dwStackSize,                                                                 
  // initial stack size,线程堆栈的大小 

LPTHREAD_START_ROUTINE lpStartAddress,           // thread function,线程函数 

LPVOID lpParameter,                                      // thread argument,参数  DWORD
dwCreationFlags,                                          
// creation option,创建时的标志  LPDWORD
lpThreadId                                                    // thread identifier,线程的ID
);

              线程的控制。

         线程的有三种状态:就绪,阻塞,运行。

         当我们在CreateThread的时候,第5个参数为CREATE_SUSPENDED标志时,线程创建后就处于挂起,即阻塞状态,否则,线程就会调用线程函数立即执行

        ResumeThread可以让线程阻塞的线程继续运行,SuspendThread可以让线程挂起。(具体用法参考MSDN)

2. 线程同步不同线程间公用同一个资源的时候,就需要进行线程同步

               为何要同步?

         要回答好这个问题我们要从栈说起。这里说的栈,和数据结构中的堆栈是不一样的。

  (穿插一个小的知识: 堆和栈的区别。

                     堆就像自己在家里做饭,想做什么就做什么,但是,最后的锅碗等还需要自己去收拾;

                     而栈就像是去餐馆吃饭,只要你点好菜,餐馆就给你提供,吃完之后锅碗什么的都不需要自己管。”, 

       这说明堆和栈的区别以及如何使用它们:

堆,可以自己完全控制,用完之后需要自己清理,处理不好就会造成内存泄漏;

栈,由操作系统分配,不需要进行管理,不用担心内存泄漏)。简单的说,栈就是一块内存区域,它是从大到小增长的,它遵循后进先出的原则(FILO,First In Last Out)。

通常,CPU的EBP和ESP是用作栈的,EBP是栈的基地址,EBP是当前栈顶的位置(栈顶永远是小于等于栈底的)。

栈的主要作用就是保存现场,函数参数传递

                如何同步?

      在Windows系统中,我们可以使用互斥量,信号量,事件,重要区段等方式进行线程同步。

重要区段仅仅可以用于同一个进程中的不同线程之间的同步,它运行与用户态,其效率是最高的。

其余的运行与内核态,可以用于不同进程间(需要在用户态和内核态进行切换)。

    信号量可以允许多个线程同时访问同一资源,互斥量是信号量的一种特殊情况

具体的用法可以参考MSDN的帮助。

写个简单使用重要区段的一个例子:

// 初始化InitializeCriticalSection(FLock);           // 初始化重要区段

// 使用方法EnterCriticalSection(FLock);                // 进入保护区 

//.. 需要保护的数据LeaveCriticalSection(FLock);               // 释放

// 释放资源DeleteCriticalSection(FLock);              // 删除重要区段另外,

消息也可以作为同步的一种手段。

也许你会说,消息必须要有UI,也就是说必须要有窗体才可以,其实不然,使用PostThreadMessage,然后利用SetWindowsHookEx来Hook线程的消息,处理我们发送的消息(这种方式是我在做注入后对注入进行控制时想到的方法),如下:

 

发送方: ::

PostThreadMessage(hThread, WM_XXX, wPar, lPar);

接收方:  ::

SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hInstance, dwThreadID);
  GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
  {
    if (PMSG (lParam)^.message == WM_XXX)
    {
      // Process
    }
    return ::CallNextHookEx(…);
  }
这种方法的好处就是我们可以发送两个参数给目标。

抱歉!评论已关闭.