使用“线程”窗口

“线程”窗口包含每行表示应用程序中一个线程的表。 默认情况下,该表列出应用程序中的所有线程,但您可以筛选列表以仅显示您感兴趣的线程。 每列都包含不同类型的信息。 您还可以隐藏某些列。 如果显示所有列,将从左到右显示以下信息:

标志列,您可以在此处标记要格外关注的线程。

活动线程列,此处黄色箭头指示一个活动线程。 箭头的轮廓指示执行在调试器中分解的线程。

“ID”列,包含每个线程的标识号。

“托管 ID”列,包含托管线程的托管标识号。

“类别”列,将线程划分为用户界面线程、远程过程调用处理程序或辅助线程。 一个特殊类别标识应用程序的主线程。

“名称”列,如果有线程,则按名称标识每个线程,否则标识为“<无名称>”。

“位置”列,显示线程运行的位置。 可以展开此位置以显示线程的完整调用堆栈。

“优先级别”列,包含系统已向每个线程分配的优先级。

“关联掩码”列,高级列,通常隐藏。 此列显示每个线程的处理器关联掩码。 在多处理器系统中,关联掩码确定线程可以在哪些处理器上运行。

“已挂起”列,包含挂起项计数。 此计数确定线程是否可以运行。

“进程名称”列,包含每个线程所属的进程。 在调试多个进程时,此列会很有用,但此列通常隐藏。

切换活动线程

任意执行以下步骤之一:

?????????? 双击任一线程。

?????????? 右击一个线程,再单击“切换到线程”。

?????????? 黄色箭头会出现在新活动线程的旁边。 箭头的灰色轮廓标识执行在调试器中分解的线程

显示线程调用堆栈

在多线程程序中,每个线程都有自己的调用堆栈。 “线程”窗口提供了一种查看这些堆栈的简便方法。

查看线程的调用堆栈,在“位置”列中,单击线程位置旁边的倒三角形。 此位置将展开以显示线程的调用堆栈。?

扩充阅读:

使用Visual Studio 2010调试并行程序

???????Visual Studio 2010对并行程序的调试提供了强大的手段,给程序设计好断点以后,可以使用Threads窗口查看当前程序的所有线程:

?

???????在图

?19?9中双击某行,可以让指定的线程成为当前“激活”的“被调试”的线程。

??????????????另外,Parallel Tasks窗口展示了当前程序所运行的所有任务:

在Parallel Stacks窗口中,则可以直观地看到每个线程的调用堆栈:

?

有关Visual Studio 2010调试器的使用方法,请查询MSDN。本书不再赘述。

另外,

? ??扩充阅读:

使用Visual Studio 2010调试并行程序

???????Visual Studio 2010对并行程序的调试提供了强大的手段,给程序设计好断点以后,可以使用Threads窗口查看当前程序的所有线程:

?

???????在图?19?9中双击某行,可以让指定的线程成为当前“激活”的“被调试”的线程。

??????????????另外,Parallel Tasks窗口展示了当前程序所运行的所有任务:

在Parallel Stacks窗口中,则可以直观地看到每个线程的调用堆栈:

?

有关Visual Studio 2010调试器的使用方法,请查询MSDN。本书不再赘述。

研究遗传算法的一大诟病就是每次运行程序的结果并不是完全一样的,有时候能找到最优解有时候找不到最优解,这就是遗传算法的概率性导致的。那么怎么评价你的方法的好坏呐,这时候就要多次独立运行程序最后取结果的平均值或者计算算法的运行成功率。那么问题就来了,遗传算法的运行时间本来就略长,尤其当测试数据集很大且数量很多的时候,做一次实验跑完所有数据的时间有时候有点让人难以接受。于是想到了使用多线程,这样就可以同时运行多组独立的实验,最后再整合所有子线程的输出数据,计算运行成功率或者取最优解的平均值即可,怀揣着这个想法,开始尝试着用多线程编程来加快实验进度。以下是这几天的学习、实验过程和结果。

本人一直用Windows下的VS 2010编程,看了很多关于多线程编程的博客和资料之后我决定不用win32的API来实现多线程(各种函数名太长看着都懒得搞),而使用pthread的windows开发包(下载地址http://www.sxzhongrui.com/pthreads-win32/ 下载任意版本,本人下载的是最新版www.sxzhongrui.com,在VS下的配置方法稍后描述)比较方便。So, 多线程编程即将搞起来~~~

第一步:在VS2010下配置pthread 下载好pthread之后解压到任意文件夹,解压之后包含三个文件夹 Pre-built.2 pthreads.2 以及QueueUserAPCEx。在配置中需要用到的只有第一个文件夹下的东西。打开Pre-built.2文件夹会开到三个文件夹分别是dll、include、lib以及一对其他文件,从这三个文件夹就可以看出接下来要怎么配置。

1.将include路径填加为VS的包含路径。 例如我的include路径是F:\C&C++\多线程编程\pthreads-w32-2-9-1-release\Pre-built.2\include。填加该路径至包含路径

打开 属性管理器->右击->属性->VC++目录->包含目录, 将要填加的目录复制粘贴进去点击确定(主意千万不要在路径前面填加“$”符号,否则出错) 2.填加库目录。同第一步,将lib文件夹的目录填加进库目录 3.填加lib文件到附加依赖项。属性管理器->右击->属性->链接器->输入->附加依赖项。将lib文件夹下的.lib文件文件名复制粘贴在该项目下,记得每一个lib文件名换行。 4.将dll文件夹下的dll文件复制粘贴到你的VS项目根目录下。就可以开始使用pthread在VS中写多线程程序了。

第二步.编程

下面是我的程序

#include"rcpsp.h"//自己编写的头文件

#include//pthread头文件,多线程的东西都在里面

//===========10个线程=========================

//每个线程是一次独立的实验,每组数据十次独立运行,所以编写十个子线程,以求快速完成实验

void* process_0(void *arg);

void* process_1(void *arg);

void* process_2(void *arg);

void* process_3(void *arg);

void* process_4(void *arg);

void* process_5(void *arg);

void* process_6(void *arg);

void* process_7(void *arg);

void* process_8(void *arg);

void* process_9(void *arg);

//==========================================

typedef struct

{

//===========Input Variables============

....

//===========Output Variables===========

....

}InputData;

int main(void)

{

pthread_t p0,p1,p2,p3,p4,p5,p6,p7,p8,p9;//定义pthread变量

InputData Data[10]; //子线程输入输出数据

//=================multi threads=========================

pthread_create(&p0,NULL,process_0,(void*)&Data[0]);

pthread_create(&p1,NULL,process_1,(void*)&Data[1]);

pthread_create(&p2,NULL,process_2,(void*)&Data[2]);

pthread_create(&p3,NULL,process_3,(void*)&Data[3]);

pthread_create(&p4,NULL,process_4,(void*)&Data[4]);

pthread_create(&p5,NULL,process_5,(void*)&Data[5]);

pthread_create(&p6,NULL,process_6,(void*)&Data[6]);

pthread_create(&p7,NULL,process_7,(void*)&Data[7]);

pthread_create(&p8,NULL,process_8,(void*)&Data[8]);

pthread_create(&p9,NULL,process_9,(void*)&Data[9]);

pthread_join(p0,NULL);

pthread_join(p1,NULL);

pthread_join(p2,NULL);

pthread_join(p3,NULL);

pthread_join(p4,NULL);

pthread_join(p5,NULL);

pthread_join(p6,NULL);

pthread_join(p7,NULL);

pthread_join(p8,NULL);

pthread_join(p9,NULL);

//==================输出数据后处理========================

....

}

以上是我主程序的大概流程,由于pthread_create()创建子线程的时候给子线程函数的传入参数只有一个,所以当你需要给子函数传递多个函数参数或者需要传出参数的时候只能定义一个结构体,将所有输入和输出数据全部包装在结构体中,然后将结构体变量的引用传入子线程函数即可。在本例中,将所有输入输出参数全部包装在结构体InputData中,由于有十个子线程,为了避免不必要的麻烦,所以定义十个变量,用来输入和输出函数参数和返回值。

关于pthread_join( , )函数,它有两个参数,具体含义可以查阅其他博文。其作用是让主线程等待子线程结束,整个main函数是主线程,如果没有pthread_join这句代码,当主线程结束的时候,所有子线程也会被终止,而不管子线程是否已经结束,而大多数情况下,主线程会很快结束,然后创建的子线程还没有执行就随着主线程的结束而结束,所以一定要加一句等待子线程结束的代码。当然还有更简便的函数pthread_exit(),也可在所有线程的最后写上phread_exit(0)来让主线程等待所有子线程的结束。

phread.h中包含很多函数,在这里就不一一介绍,具体可参阅https://www.sxzhongrui.com/pthreads-win32/manual/index.html

关于创建多少个线程才能效率更好的问题,网上和书上大部分推荐创建的线程数为CPU核数N 的2倍或者2*N+2个。所以这多线程和硬件关系特别大,如果是单核处理器,那完全不建议使用多线程,不然不但不会提高运行效率,反而线程之间的切换会占去很大一部分开销。

那么,我的实验运行速度提高了多少呐?? 答案是:没有提高。

让两台机子分别跑同一个数据集,一个采用上面的多线程方法,另一个串行执行每一组实验,经过对比,很悲伤的发现,串行的实验组跑得更快,当然和遗传算法本身也有很大的关系,每次一初始化不同,变异、交叉概率不同导致的找到解的时间就会不同,但是,这样的结果也是够让我伤心的了,搞了两天的多线程编程,查阅各种博客、去图书馆查资料,改程序,调程序,结果~~效果并不理想,也许是我的实验方法有问题,亦或是我的程序有问题,反正,多线程并没有加快我的实验进度。但是以后还是会尝试用多线程或者并行编程来加快遗传算法的实验速度的。 PS:原博文地址http://www.sxzhongrui.com/hxingxing/p/4599843.html

转载(原文地址):VS2010 多线程编程

多线程测试实例

此时在多核CPU下,主线程和子线程可同时运行;

#include

#include

#include

using namespace std;

DWORD WINAPI MyThreadProc1(LPVOID lpParameter);

DWORD WINAPI MyThreadProc2(LPVOID lpParameter);

int index = 0;

int i = 0 , y = 0;

int main()

{

HANDLE handle1,handle2;

handle1 = CreateThread(NULL,0,MyThreadProc1,NULL,0,NULL);

handle2 = CreateThread(NULL,0,MyThreadProc2,NULL,0,NULL);

if(NULL == handle1)

{

cout<<"Create Thread failed !"<

return -1;

}

if(NULL == handle2)

{

cout<<"Create Thread failed !"<

return -1;

}

CloseHandle(handle1);

CloseHandle(handle2);

cout<<"The Main Thread is Running !"<

system("PAUSE");

return 0;

}

DWORD WINAPI MyThreadProc1(LPVOID lpParameter)

{

cout<<"The MyThreadProc1 is Running !"<

return 0;

}

DWORD WINAPI MyThreadProc2(LPVOID lpParameter)

{

cout<<"The MyThreadProc2 is Running ! "<

return 0;

}

虽然cpu是多核的很久了,但是很多时候都是串行执行,降低了执行的速率。因为项目需要开启额外线程进行信号的获取。(下篇决定学习一下并行执行) 创建线程貌似此函数就够了,只知道第三个参数是函数参数

handle1 = CreateThread(NULL,0,MyThreadProc1,NULL,0,NULL);

创建线程具体参数详解:http://www.sxzhongrui.com/del/category/174761.html 函数原型

function CreateThread(

lpThreadAttributes: Pointer; {安全设置}

dwStackSize: DWORD; {堆栈大小}

lpStartAddress: TFNThreadStartRoutine; {入口函数}

lpParameter: Pointer; {函数参数}

dwCreationFlags: DWORD; {启动选项}

var lpThreadId: DWORD {输出线程 ID }

): THandle; stdcall; {返回线程句柄}

返回值:线程句柄(类似指针) 不管线程属于哪个进程,系统中是平等的。优先级相同情况下,系统在相同的时间间隔(很小很小)来运行每个线程。

对象区别句柄只是使用对象-有句柄的对象一般都是系统级别的对象(或叫内核对象)-一般把句柄提交到某个函数(一般是系统函数)后指针可读写对象相同点内存中的一小块数据(一般用结构描述),

2. 参数1:安全设置 lpThreadAttributes 是指向 TSecurityAttributes 结构的指针, 一般都是置为 NULL(没有访问限制) 3. 参数2:堆栈大小(栈:私有的||堆:公用的) 每个线程都有自己独立的堆栈(也拥有自己的消息队列).默认值是 0, 这表示使用系统默认的大小, 默认和主线程栈的大小一样, 如果不够用会自动增长;

对象不同点用途堆先进先出栈(堆栈)先进后出适合存取临时而轻便的变量, 主要用来储存局部变量;相同点都是进程中的内存区域

4. 参数3:入口函数指针(即函数地址) 入口函数的标准定义, 这个函数的标准返回值应该是 DWORD。(可以通过退出码来判断线程是否已退出.) 线程退出后, 我们用 GetExitCodeThread 函数获取的退出码就是这个返回值! 如果线程没有退出, GetExitCodeThread 获取的退出码将是一个常量 STILL_ACTIVE (259); 5. 参数4:函数参数 线程入口函数的参数是个无类型指针(Pointer), 用它可以指定任何数据; 6. 参数5:启动选项 CreateThread 的倒数第二个参数 dwCreationFlags(启动选项) 有两个可选值: 0: 线程建立后立即执行入口函数; CREATE_SUSPENDED: 线程建立后会挂起等待. ResumeThread 恢复线程的运行; SuspendThread 挂起线程. 这两个函数的参数都是线程句柄, 返回值是执行前的挂起计数. PS:挂起计数(count≥0) SuspendThread ,count+=1; ResumeThread ,count -=1; if count == 0 , 线程run; > 0 时会挂起. 如果被 SuspendThread 多次, 同样需要 ResumeThread 多次才能恢复线程的运行. ResumeThread 和 SuspendThread 分别对应 TThread 的 Resume 和 Suspend 方法, 很好理解. 7. 参数6:输出线程ID

ID 比句柄更轻便.在主线程中 GetCurrentThreadId、MainThreadID获取的都是主线程的 ID线程的 ID 是唯一的; 而句柄可能不只一个, 譬如可以用 GetCurrentThread 获取一个伪句柄、可以用 DuplicateHandle 复制一个句柄等等.ID 比句柄更轻便.在主线程中 GetCurrentThreadId、MainThreadID获取的都是主线程的 ID.