程序是计算机指令的几何,以文件的形式存在磁盘上。进程被定义为正在运行的程序的实例,是在进行地址空间中的一次执行活动。一个程序可以对应多个进程,如可以通过打开多个Word程序,每个word的应用就是一个进程。同时一个进程可以访问多个程序。进程是系统资源申请、调度、运行的独立单位。程序不占用系统的运行资源。

   进程由两部分组成:(1)操作系统用管理进程的内核对象,一个OS内部分配的一个内存块(数据结构),并且只对操作系统可见,进程只能通过"OS提供的API"来操作这个“内存对象”;(2)地址空间,包含进程所有可执行模块,或者DLL模块的代码和数据,以及可以用于进程动态分配的空间,如线程的栈空间Stacks,以及堆空间Heap。

  进程是线程的容器,一个进程至少拥有一个主线程,被称为“主线程”,即maiin函数线程,即主线程进入点。主线程可以创建其他线程。进程是所有线程执行环境,是真正完成代码执行。这些线程“同时”执行进程地址空间中的代码。不同的进程之间不能相互访问。同一进程的不同线程之间可以相互访问。

  线程由两部分组成:(1)线程的内核对象。 被OS创建,用于被OS管理线程的最小单位(2)线程栈Stack。用于维护执行线程过程中所需要的所有函数参数和局部变量。

  当进程创建线程时,OS首先创建“线程内核对象”,OS从进程的地址空间分配内存供其“线程栈”使用。新线程可以访问进程的内核对象的所有“进程的内核对象的所有句柄”“进程中的所有内存”“本进程中的所有线程的堆栈”。所以单个进程间的所有线程之间可以非常容易相互通信。

  由于创建线程的资源比较少,一般采用单进程多线程解决问题。即所谓的“多线程编程”艺术。不采用多进程解决问题的原因(1)创建进程的代价大,且进程之间的通信比较困难;(2)进程之间切换时代价也比较大,不同进程需要切换整个地址空间,但是线程切换的只是少量的执行环境。

  多线程编程中,多线程采用时间片轮转的方式,在宏观上实现“同时”运行。如果计算机有多CPU或者多核,则可以真正实现多线程编程,且真正并行编程。

  创建线程函数的WinOSAPI:CreateThread(),此函数创建一个线程,函数原型如下:

static HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpsa,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE pfnThreadProc,
void* pvParam,
DWORD dwCreationFlags,
DWORD* pdwThreadId
) throw( );
  lpsa:  新线程的安全特性。如果为NULL,则采用默认的安全性。
  dwStackSize  新线程的堆栈大小。即线程可以将多少地址空间用于自己的栈,以字节Byte为单位。OS会把此值四舍五入为一个合理的页面大小。一般X86使用页面大小4KB(WinOS需要保证分配堆栈是页面大小的整倍数)。
  pfnThreadProc  新线程的线程过程。即指向一个函数的指针,这个将由新创建的线程执行,即表型县县城的其实地址,即此线程的入口地址(同主线程的Main函数一样),函数名自定义,但是需要采用以下形式进行声明,入口函数的参数LPVOID的类型,返回DWORD类型。
DWORD WINAPI ABCThreadProcABC( _In_ LPVOID lpParameter );
  pvParam  将传递的参数传递给线程过程。  可以是一个数值,或者是指向其他信息的指针。
  dwCreationFlags  创建标志(0个或CREATE_SUSPENDED)。  即如果为CREATE_SUSPENDED,则线程创建后处于暂停状态,指导程序调用ResumeThread,开始执行。如果为0,则新线程创建后立即执行。
  pdwThreadId  [out] ,若成功,接收新创建的线程的线程ID ,DWORD变量的地址。  在Win95或者后的,必须执行一个变量来接受新创建线程的ID。
  WinOS环境下创建线程需要注意:
  (1)需要使用WinOS的API函数,要包含windows.h的头文件。
  (2)用HANDLE  handAAA对象接受新创建的线程句柄,当不在需要对先创建的线程操作时,调用CloseHandle(handAAA),将此线程关闭。注意调用此函数不是终止新创建的线程,而是表示在主线程中对新创建的线程的而引用不感兴趣,关闭线程句柄。这样新创建的线程的引用计数就会计数-1,若果新创建线程执行完毕后,系统也会递减改线程“内核对象”的使用计数。当使使用计数递减为0后,则WINOS则释放此线程内核对象 。如果主线程没有关闭句柄,则系统会易制保留一个对新创建线程的引用。这样直到“进程”执行完毕后,才能释放此线程的资源。所以在主线程中,如果不需要其他新建线程的句柄时,则可以将其及时关闭。
  (3)如果再在一个线程中使用 void Sleep(  _In_ DWORD dwMilliseconds), 则可以使本线程暂时一段时间,以毫秒为单位。
  (4)在主线程可以使用system("pause"),这样可以保证主线程不会退出,给其他线程保留足够的时间。或者也是使用Sleep函数。
  (5)多线程相互之间共享资源时,需要处理好线程之间的同步问题。在一个线程访问共享变量时,其他线程则不能访问。
    利用互斥对象实现多线程之间的共享变量。Mutex,是内核对象,保证多线程对贡献变量的互斥访问权。此对象包含使用数量,以及线程ID,以及计数器。其中线程ID表示当前拥此互斥对象的线程ID,计数器表示线程拥有虎池对象的次数。在WinOS系统中使用如下函数原型创建互斥内核对象。调用后,可以打开或者关闭一个命名或者匿名的互斥对象。调用成功将返回互斥对象的句柄。当线程对共享对象访问结束后,应该释放改对象的使用权。通过ReleaseMutex(Handle),如果释放成功返回非0,失败返回0.互斥对象的处理原则:谁拥有,谁释放。因为互斥对象中被WinOS设置了与之相关的线程ID,如果释放不是被设置ID,则不能被其他线程操作。
    当线程第一次拥有互斥对象时(1)设置被线程ID给互斥对象,(2)设置互斥对象当前线程使用(未释放)互斥对象的次数+1。
    如果请求的线程ID与互斥对象中的线程ID相等,则可以继续请求互斥对象,即使本线程此前没有释放互斥对象,此时的影响是互斥对象中的使用次数+1。每调用一次释放releaseMutex,互斥对象内部的引用-1。直到释放为0,则其他线程可以请求到此Mutex对象。
    线程需要通过主动请求共享对象的使用权才有可能获取共享对象拥有权。使用DWord WaitForSingleObject(handler, dwMilliseconds);参数hHandler获取请求对象的句柄。即互斥对象的句柄hMutex, 一旦该对象有信号,则此线程就通过此函数获取此互斥对象。否则,此线程一直停留在此函数的位置。则暂停线程。参数2,指定等待的时间间隔,毫秒单位,如果超过此事件,则此函数将返回。或者0,立即返回,或者INFINITE,无限等待下去。
    调用WaitForSingleObject后此线程一直等待下去,党(1)指定的对象为有信号,则返回,(2)超过设定的等待时间。此函数会返回(1)WAIT_OBJECT_0:请求对象有信号;(2) WAIT_TIMEOUT:超过等待时间,且请求对象信号; WAIT_ABANDONED:请求对象为互斥对象,此前的线程在执行完毕没有释放此对象,则此时当前线程获取请求对象有有权,且设定互斥对象为无信号状态。
HANDLE WINAPI CreateMutex(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,  如果为NULL,则使用默认的安全性
_In_ BOOL bInitialOwner,  即确定互斥对象的初始拥有者,否则此线程将不能后的所创建的互斥对象的所有权。True,则本线程初始拥有此互斥对象,如果本线程不释放,则其他线程不能等待拥有。
_In_opt_ LPCTSTR lpName  指定互斥对象的名称,如果为NULL,则是匿名互斥对象。
);
 // ConsoleTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int tick = ;
HANDLE hMutex = NULL;
DWORD WINAPI funName1(LPVOID para)
{
while (true)
{
WaitForSingleObject(hMutex, INFINITE);
if (tick > )
cout << "\n threadAAAAAA sell 1 tick " << tick-- << endl;
else
break;
ReleaseMutex(hMutex);
}
return ;
}
DWORD WINAPI funName2(LPVOID para)
{
while (true)
{
WaitForSingleObject(hMutex, INFINITE);
if (tick > )
cout << "\n threadBBBBB sell 1 tick " << tick-- << endl;
else
break;
ReleaseMutex(hMutex);
}
return ;
} int _tmain(int argc, _TCHAR* argv[])
{
HANDLE handle1 = nullptr;
HANDLE handle2 = nullptr;
DWORD threadID1 = NULL;
DWORD threadID2 = NULL;
handle1 = CreateThread(NULL, , funName1, NULL, , &threadID1);
handle2 = CreateThread(NULL, , funName2, NULL, , &threadID2); cout << "main Thread is running..." << handle1 << threadID1 << endl;
cout << "main Thread is running..." << handle2 << threadID2 << endl;
cout << "--------------------" << endl;
CloseHandle(handle1);
CloseHandle(handle2);
cout << "main Thread is running..." << handle1 << threadID1 << endl;
cout << "main Thread is running..." << handle2 << threadID2 << endl;
hMutex = CreateMutex(NULL, false, _T("AAAA"));
//
system("pause");
return ;
}
  在C++中的NULL,即为0,定义如下:
#ifdef __cplusplus
#define NULL 0
#else /* __cplusplus */

  

MFC中的多线程的更多相关文章

  1. 转:MFC中创建多线程

    MFC中创建多线程   MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员 ...

  2. 多线程编程之二 ---MFC中的多线程开发

    下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...

  3. MFC中创建多线程

    1.   列举几种进程的同步机制,并比较其优缺点. 原子操作    信号量机制   自旋锁    管程,会合,分布式系统 2.   进程之间通信的途径 共享存储系统       消息传递系统      ...

  4. C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)

    一.什么是C运行时库 1)C运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数. 2)C 语言是所谓的“ ...

  5. VC++中的C运行时库浅析(控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)

    1.概论 运行时库是程序在运行时所需要的库文件,通常运行时库是以LIB或DLL形式提供的.C运行时库诞生于20世纪70年代,当时的程序世界还很单纯,应用程序都是单线程的,多任务或多线程机制在此时还属于 ...

  6. MFC 中线程传递CString 是不安全的 转

     MFC 中线程传递CString 是不安全的       在MFC中,向线程传递CString变量参数时,很容易犯一个错误,就是使用一个超出生存期的变量,在主函数中定义的CString变量是局部变量 ...

  7. MFC中线程相关知识

    MFC中把线程分为两种类型,UI线程和工作者线程. MFC中启动一个线程的最好方法是调用AfxBeginThread,有两个版本,一个用于启动Ui线程,另外一个用于启动工作者线程.在MFC程序中,只有 ...

  8. MFC中获取各个窗口之间的句柄或者指针对象的方法

    MFC在非常多的对话框操作中,我们常常要用到在一个对话框中调用还有一个对话框的函数或变量.能够用例如以下方法来解决.    HWND hWnd=::FindWindow(NULL,_T("S ...

  9. OpenGL在MFC中的使用总结(一)——基本框架

    项目中要画3D显示的模型,于是要用到OpenGL,加上是在MFC中,并且是在MFC中的ActiveX中使用.再并且鉴于他们程序主框架的设定.常规的方法还不一定能实现.所以还是查过不少资料,在此一一总结 ...

随机推荐

  1. PHPstorm配置PHPunit对composer引入的php代码进行单元测试

    1. 如何安装PHPunit,这里不展述(如需打断点debug测试,安装PHP的xdebug扩展方法也不展开说了 https://xdebug.org/) 2.如何进行配置 以 PHP设计模式的代码为 ...

  2. 黄聪:V2010中C#实现友好的等待任务完成时,出现的多线程悬浮窗体

    实现效果如下: 项目已经打包后,大家直接下载吧:[HCWaitForm.rar]

  3. 【转】java内存分配和String类型的深度解析

    一.引题 在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析关于String的许多令人迷惑的问题.下面是本 ...

  4. LAMP的安装和注意事项

    LAMP--Linux+Apache(httpd)+MySQL+PHP,是常用的web服务器架构,下面接受编译安装的过程,以及出现的错误. 注意事项: 1. 扩展epel源:参照:http://www ...

  5. 【精华】部署与管理ZooKeeper(转)

    部署与管理ZooKeeper(转) 本文以ZooKeeper3.4.3版本的官方指南为基础:http://zookeeper.apache.org/doc/r3.4.3/zookeeperAdmin. ...

  6. Quartz教程

    Quartz教程   Quartz教程四--Trigger介绍 Quartz教程八--SchedulerListener 08-24 Quartz教程七--TriggerListener和JobLis ...

  7. web前端知识体系大全【欢迎补充】

    大约在几个月之前,让我看完了<webkit技术内幕>这本书的时候,突然有了一个想法.想把整个web前端开发所需要的知识都之中在一个视图中,形成一个完整的web前端知识体系,目的是想要颠覆人 ...

  8. C#遍历XmlDocument对象所有节点名称、类型、属性(Attribute)

    C#遍历XmlDocument对象所有节点名称.类型.属性(Attribute) 源码下载 代码 static void Main(string[] args) { System.Xml.XmlDoc ...

  9. 在 ubuntu1604 中 搭建 i 屁 sec 虚拟专用连接服务器

    1.wget https://git.io/vpnsetup -O vpnsetup.sh 2.vim vpnsetup.sh 修改一些内容: 主要有三个参数:IPSEC的预共享秘钥,用户名,密码 3 ...

  10. WPF TabControl控件-事件相关问题

    TabControl控件的TabItem的Content元素,例如:DataGrid控件,在对事件的处理时,需要对事件的源引起关注,当需要处理DataGrid的事件时,事件会传递到TabControl ...