C++多线程编程分析-线程间通信

   上文我们介绍了如何建立一个简单的多线程程序,多线程之间不可避免的需要进行通信。相比于进程间通信来说,线程间通信无疑是相对比较简单的。

   首先我们来看看最简单的方法,那就是使用全局变量(静态变量也可以)来进行通信,由于属于同一个进程的各个线程是处于同一个进程空间中的,并且它们共享这个进程的各种资源,因此它们都可以毫无障碍的访问这个进程中的全局变量。当需要有多个线程来访问一个全局变量时,通常我们会在这个全局变量前加上volatile声明,来告诉编译器这个全局变量是易变的,让编译器不要对这个变量进行优化(至于编译器到底有没有按照你的要求来对volatile进行处理这个暂且不理)。

   下面贴出一段简单的示例代码:

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
volatile int ThreadData = 0;
void ThreadProcess()
{
    for(int i=0; i<6; i++)
    {
        ThreadData += 1000;
        Sleep(1000);
        printf("Sub  Thread Tick %5d! %5d\n",(i+1)*1000, ThreadData);
    }
    printf("Exit Sub Thread!\n");
     }
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hThread;
    DWORD ThreadID;
    hThread=CreateThread(NULL,
                     0,
                     (LPTHREAD_START_ROUTINE)ThreadProcess,
                     NULL,
                     0,
                     &ThreadID);
    
    for(int i=0; i<10; i++)
    {
        ThreadData -= 600;
        Sleep(600);
        printf("Main Thread Tick %5d! %5d\n", (i+1)*600, ThreadData);
    }
    printf("Main Thread Loop Finished! \n");
    system("pause");
    return 0;
}

   除了全局变量之外,还有其他的方法,比如利用消息机制等来实现线程间通信。这个就不详细解释了,关于消息机制,详情请看Windows消息机制概述 。 

   下面,关于多线程中的全局变量,我来介绍点有点偏题的东西:
线程局部存储(TLS)
    进程中的全局变量与函数内定义的静态(static)变量,是各个线程都可以访问的共享变量。在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。
  如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量(被称为static memory local to a thread 线程局部静态变量),就需要新的机制来实现。这就是TLS。
  线程局部存储在不同的平台有不同的实现,可移植性不太好。 
  方法一:每个线程创建时系统给它分配一个LPVOID指针的数组(叫做TLS数组),这个数组从C编程角度是隐藏着的不能直接访问,需要通过一些C API函数调用访问。首先定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量。一个线程使用TLS时,第一步在线程内调用TlsAlloc()函数,为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot)关联起来,例如获得一个索引变量:
  global_dwTLSindex=TLSAlloc();
  注意,此步之后,当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说,不同线程虽然看起来用的是同名的TLS数组索引变量,但实际上各个线程得到的可能是不同DWORD值。其意义在于,每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制,所以在如此大费周折。
  第二步,为当前线程动态分配一块内存区域(使用LocalAlloc()函数调用),然后把指向这块内存区域的指针放入TLS数组相应的槽中(使用TlsValue()函数调用)。
  第三步,在当前线程的任何函数内,都可以通过TLS数组的索引变量,使用TlsGetValue()函数得到上一步的那块内存区域的指针,然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。
  最后,如果不再需要上述线程局部静态变量,要动态释放掉这块内存区域(使用LocalFree()函数),然后从TLS数组中放弃对应的槽(使用TlsFree()函数)。
  方法二:
  直接声明这个变量是各个线程有自己拷贝的线程局部静态变量:
  __declspec( thread ) int var_name;

你可能感兴趣的:(堆栈,线程,c++,开发语言,后端)