科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件深入浅出Win32多线程程序设计之基本概念

深入浅出Win32多线程程序设计之基本概念

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

从单进程单线程到多进程多线程是操作系统发展的一种必然趋势。

作者:宋宝华 来源:天极开发 2007年10月16日

关键字: Win32 多线程 程序设计 概念

  • 评论
  • 分享微博
  • 分享邮件
引言

  从单进程单线程到多进程多线程是操作系统发展的一种必然趋势,当年的DOS系统属于单任务操作系统,最优秀的程序员也只能通过驻留内存的方式实现所谓的"多任务",而如今的Win32操作系统却可以一边听音乐,一边编程,一边打印文档。

  理解多线程及其同步、互斥等通信方式是理解现代操作系统的关键一环,当我们精通了Win32多线程程序设计后,理解和学习其它操作系统的多任务控制也非常容易。许多程序员从来没有学习过嵌入式系统领域著名的操作系统VxWorks,但是立马就能在上面做开发,大概要归功于平时在Win32多线程上下的功夫。

  因此,学习Win32多线程不仅对理解Win32本身有重要意义,而且对学习和领会其它操作系统也有触类旁通的作用。

  进程与线程

  先阐述一下进程和线程的概念和区别,这是一个许多大学老师也讲不清楚的问题。

  进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体。而进程则不同,它是程序在某个数据集上的执行,是一个动态实体。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消,反映了一个程序在一定的数据集上运行的全部动态过程。

  线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位。线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

  线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。

  根据进程与线程的设置,操作系统大致分为如下类型:

  (1)单进程、单线程,MS-DOS大致是这种操作系统;

  (2)多进程、单线程,多数UNIX(及类UNIX的LINUX)是这种操作系统;

  (3)多进程、多线程,Win32(Windows NT/2000/XP等)、Solaris 2.x和OS/2都是这种操作系统;

  (4)单进程、多线程,VxWorks是这种操作系统。

  在操作系统中引入线程带来的主要好处是:

  (1)在进程内创建、终止线程比创建、终止进程要快;

  (2)同一进程内的线程间切换比进程间的切换要快,尤其是用户级线程间的切换。另外,线程的出现还因为以下几个原因:

  (1)并发程序的并发执行,在多处理环境下更为有效。一个并发程序可以建立一个进程,而这个并发程序中的若干并发程序段就可以分别建立若干线程,使这些线程在不同的处理机上执行。

  (2)每个进程具有独立的地址空间,而该进程内的所有线程共享该地址空间。这样可以解决父子进程模型中,子进程必须复制父进程地址空间的问题。

  (3)线程对解决客户/服务器模型非常有效。

  Win32进程

  1、进程间通信(IPC)

  Win32进程间通信的方式主要有:

  (1)剪贴板(Clip Board);

  (2)动态数据交换(Dynamic Data Exchange);

  (3)部件对象模型(Component Object Model);

  (4)文件映射(File Mapping);

  (5)邮件槽(Mail Slots);

  (6)管道(Pipes);

  (7)Win32套接字(Socket);

  (8)远程过程调用(Remote Procedure Call);

  (9)WM_COPYDATA消息(WM_COPYDATA Message)。

  2、获取进程信息

  在WIN32中,可使用在PSAPI .DLL中提供的Process status Helper函数帮助我们获取进程信息。

  (1)EnumProcesses()函数可以获取进程的ID,其原型为:

BOOL EnumProcesses(DWORD * lpidProcess, DWORD cb, DWORD*cbNeeded);

  参数lpidProcess:一个足够大的DWORD类型的数组,用于存放进程的ID值;

  参数cb:存放进程ID值的数组的最大长度,是一个DWORD类型的数据;

  参数cbNeeded:指向一个DWORD类型数据的指针,用于返回进程的数目;

  函数返回值:如果调用成功,返回TRUE,同时将所有进程的ID值存放在lpidProcess参数所指向的数组中,进程个数存放在cbNeeded参数所指向的变量中;如果调用失败,返回FALSE。

  (2)GetModuleFileNameExA()函数可以实现通过进程句柄获取进程文件名,其原型为:

DWORD GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,LPTSTR lpstrFileName, DWORD nsize);

  参数hProcess:接受进程句柄的参数,是HANDLE类型的变量;

  参数hModule:指针型参数,在本文的程序中取值为NULL;

  参数lpstrFileName:LPTSTR类型的指针,用于接受主调函数传递来的用于存放进程名的字符数组指针;

  参数nsize:lpstrFileName所指数组的长度;

  函数返回值:如果调用成功,返回一个大于0的DWORD类型的数据,同时将hProcess所对应的进程名存放在lpstrFileName参数所指向的数组中;加果调用失败,则返回0。

  通过下列代码就可以遍历系统中的进程,获得进程列表:

//获取当前进程总数
EnumProcesses(process_ids, sizeof(process_ids), &num_processes);
//遍历进程
for (int i = 0; i < num_processes; i++)
{
 //根据进程ID获取句柄
 process[i] = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0,
 process_ids[i]);
 //通过句柄获取进程文件名
 if (GetModuleFileNameExA(process[i], NULL, File_name, sizeof(fileName)))
  cout << fileName << endl;
}
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章