“主线程”探究,谈谈我对“主线程”的理解

来源:互联网 发布:足球比赛视频分析软件 编辑:程序博客网 时间:2024/05/16 08:01

   今天看到论坛上有人问关于”主线程“的问题,写篇文章来谈谈自己的看法。

  我认为”主线程“是一个经验概念,所谓经验概念,就是说程序员印象中有这么个东西,但是在系统层面,并没有对线程进行”主“和”辅“的区分。为什么大家会有这种”主线程“的概念的,可能是由于常见的编程框架如MFC、VCL、包括SDK都存在一个共同的特点,从某个函数开始执行,这个函数执行完毕后,程序退出。那么这个函数所在的线程就可以称之为”主线程“。

  对于MFC,这个函数可以是CMyApp::InitializeInstance;对于VCL,这个函数可以是dpr文件中的begin和end之间的部分;对于SDK,这个函数可以是man函数或者WinMain函数。但所有这些函数都并非程序真正的入口点。

  VC编译的可执行程序,入口点无外乎四个:

mainCRTStartup             CUI程序的入口点

wmainCRTStartup          基于UNICODE的CUI程序的入口点

WinMainCRTStartup      GUI程序的入口点

wWinMainCRTStartup   基于UNICODE的GUI程序的入口点

  这些入口点函数的实现代码就在C库源码中,查看这些代码最简单的办法就是在VC环境中调试运行你的程序,暂停到主函数的某一行,然后查看调用栈,真正的入口点函数就在栈的下方某个位置(前提是安装VC的时候选择同时安装C库源代码)。

  这些C库内建的入口点函数做的事情主要是初始化全局变量,调用主函数,析构全局变量和其他一些操作,最终调用ExitProcess函数退出进程(从这里可以看到,全局对象的构造函数会早于主函数执行)。也就是说,有一个线程调用了主函数,也负责最终程序的退出,这就是经验中的”主线程“。

  ”进程中的所有线程都退出,程序才会退出“,错,只要有一个线程调用了ExitProcess终止进程,进程就会退出,不必等候其他线程。终止进程的可以是”主线程“,也可以是某一个平凡的线程。

  一个例子:

#include <Windows.h>#include <stdio.h>//修改入口点为我们的自定义函数#pragma comment(linker, "/Entry:SlxEntry")DWORD __stdcall Thread(LPVOID lpParam){    DWORD dwEntryThreadId = (DWORD)lpParam;    DWORD dwCurrentThreadId = GetCurrentThreadId();    DWORD dwIndex;    printf("  本工作线程%lu由主线程%lu创建,开始执行...\n", dwCurrentThreadId, dwEntryThreadId);    for (dwIndex = 0; dwIndex < 10; dwIndex += 1)    {        printf("  工作线程%lu工作中%lu...\n", dwCurrentThreadId, dwIndex + 1);        Sleep(1000);    }    printf("  工作线程%lu退出...\n", dwCurrentThreadId);    return 0;}VOID SlxEntry(){    HANDLE hThread;    DWORD dwWorkThreadId = 0;    DWORD dwCurrentThreadId = GetCurrentThreadId();    printf("主线程%lu开始...\n", dwCurrentThreadId);    hThread = CreateThread(NULL, 0, Thread, (LPVOID)dwCurrentThreadId, 0, &dwWorkThreadId);    CloseHandle(hThread);    printf("创建工作线程%lu...\n", dwWorkThreadId);    printf("主线程%lu退出...\n", dwCurrentThreadId);}
  入口点线程(即”主线程“)退出了,但是工作线程还在,进程不会退出。


原创粉丝点击