进程与线程基础

程序: 计算机指令的集合,以文件的形式存储在磁盘上

进程: 正在运行是程序实例,以是一个程序在其自身的地址空间的一次执行活动。进程有一个进程管理的内核对象和地址空间组成。

线程: 程序执行的最小单元。每个进程至少一个线程,进程是线程的容器。线程是CPU调度与运行的最小单位,而进程是资源分配的最小单位。线程由线程内核对象和线程栈组成。

Windows下线程的创建

windows下创建线程的API:

HANDLE WINAPI CreateThread(
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in_opt __deref __drv_aliasesMem LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out_opt LPDWORD lpThreadId
);

lpThreadAttributes: 线程内核对象的安全属性,传入NULL,表示使用默认安全属性。

dwStackSize: 线程栈空间大小,0表示默认大小

lpStartAddress: 新线程所执行的线程函数地址,该函数的名称随意,但必须遵照下面的声明形式:

DWORD WINAPI ThreadProc( LPVOID lpThreadParameter );

lpParameter: 传递给线程函数的参数

dwCreationFlags: 控制线程创建的附加标志,设置为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread(), 如果是0,线程创建后立即执行。

lpThreadId: 该参数是一个返回值,用来接收线程ID.

线程创建实例:

#include <Windows.h>
//线程函数
DWORD _stdcall ThreadProc (LPVOID lPparameter)
{
for (int i = 0; i < 100; ++i)
{
cout << "\n[" << i <<"] Thread1 running!";
}
return 0;
} int _tmain(int argc, _TCHAR* argv[])
{
//创建线程
HANDLE hThread;
hThread = ::CreateThread(NULL,0,&ThreadProc,NULL,0,NULL); ::WaitForSingleObject(hThread,INFINITE); //等待子线程运行结束
::CloseHandle(hThread);
cout << "\nMain thread finished!";
return 0;
}

注:上面的CloseHandle函数不是终止新创建的线程,而只是关闭线程句柄。当关闭该线程句柄时该线程的内核对象引用计数减1,当新线程执行结束后,内核对象引用计数也递减,当引用计数为0时,系统释放该线程内核对象。因此,在程序中,当不需要线程句柄时,因将它关闭。

_beginthreadex

当程序使用CRT(C运行库)时,尽量使用_beginthreadex _endthreadex来创建或结束进程。因为使用CreateThread创建进程时,如果使用了C运行库的一些函数,可能会造成一些问题。

_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()

还有一组类似的函数,AfxBeginThread()AfxEndThread(),它是MFC层面的线程包装函数,当使用MFC类库时,尽量使用这组函数来创建线程。

线程同步

同步: 按照预定的先后次序进行运行。

多线程面临的主要问题就是同步,实现线程同步的机制一般有四种:互斥量、信号量、事件、临界区。

线程同步例子:

int g_tickets = 100;
HANDLE g_hMutex; //通过互斥对象实现同步
HANDLE g_hEvent; //通过事件对象实现线程同步
CRITICAL_SECTION g_cs; //使用临界区对象实现线程同步 unsigned int _stdcall ThreadProc1 (LPVOID lPparamter)
{
bool sell_out = false;
while (!sell_out)
{
//::WaitForSingleObject(g_hMutex,INFINITE); //请求互斥对象
//::WaitForSingleObject(g_hEvent,INFINITE); //请求事件对象
EnterCriticalSection(&g_cs); //进入临界区
if (g_tickets > 0)
{
cout << "thread1 sell ticket: " << g_tickets-- << endl;
}
else
{
sell_out = true;
}
//::ReleaseMutex(g_hMutex); //访问结束后,释放互斥对象
//::SetEvent(g_hEvent); //将事件对象置为有信号状态,允许其他等待该对象的线程可调度
::LeaveCriticalSection(&g_cs); //离开临界区
}
return 0;
} unsigned int _stdcall ThreadProc2 (LPVOID lPparamter)
{
bool sell_out = false;
while (!sell_out)
{
//::WaitForSingleObject(g_hMutex,INFINITE);
//::WaitForSingleObject(g_hEvent,INFINITE);
::EnterCriticalSection(&g_cs);
if (g_tickets > 0)
{
cout << "thread2 sell ticket: " << g_tickets-- << endl;
}
else
{
sell_out = true;
}
//::ReleaseMutex(g_hMutex);
//::SetEvent(g_hEvent);
::LeaveCriticalSection(&g_cs);
}
return 0;
} typedef unsigned int (_stdcall *pThreadProc)(LPVOID); int _tmain(int argc, _TCHAR* argv[])
{
const int THREADNUM = 2;
pThreadProc threadProcs[THREADNUM];
threadProcs[0] = &ThreadProc1;
threadProcs[1] = &ThreadProc2;
HANDLE hThreads[THREADNUM];
for (size_t threadIndex = 0; threadIndex < THREADNUM; ++threadIndex)
{
hThreads[threadIndex] = (HANDLE)::_beginthreadex(NULL,0,threadProcs[threadIndex],NULL,0,NULL);
}
//g_hMutex = ::CreateMutex(NULL,false,NULL); //使用互斥对象实现线程同步
//g_hEvent = ::CreateEvent(NULL,FALSE,FALSE,NULL);//使用自动重置事件对象实现同步
//::SetEvent(g_hEvent);
::InitializeCriticalSection(&g_cs); //使用临界区对象实现线程同步
//等待所有线程结束
::WaitForMultipleObjects(THREADNUM,hThreads,TRUE,INFINITE);
::DeleteCriticalSection(&g_cs); //释放临界区对象
cout << "\nMain thread finished!";
return 0;
}

使用互斥量、事件对象、临界区实现线程同步的总结:

互斥量和事件对象都属于内核对象,使用内核对象进行线程同步时,速度较慢。但使用内核对象可以在多个进程的各个线程间进行同步。

临界区同步方式工作在用户状态,同步速度快。故在编写多线程程序时,首选使用临界区对象进行同步。

多线程学习资料:

http://blog.csdn.net/morewindows/article/details/7392749

http://www.cnblogs.com/P_Chou/archive/2012/06/10/basic-of-thread.html

http://www.cnblogs.com/chengmin/archive/2011/09/26/2192421.html

Windows多线程基础的更多相关文章

  1. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  2. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  3. 总结windows多线程同步互斥

    windows多线程同步互斥--总结 我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同 ...

  4. windows多线程同步互斥--总结

    我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同步--临界区 windows多线程同步 ...

  5. Windows多线程编程入门

    标签(空格分隔): Windows multithread programming 多线程 并发 编程 背景知识 在开始学习多线程编程之前,先来学习下进程和线程 进程 进程是指具有一定独立功能的程序在 ...

  6. Java 多线程基础(一)基本概念

    Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

  7. C++多线程基础教程

    目录 1 什么是C++多线程? 2 C++多线程基础知识 2.1 创建线程 2.2 互斥量使用 lock()与unlock(): lock_guard(): unique_lock: conditio ...

  8. Windows内核基础知识-8-监听进程、线程和模块

    Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...

  9. Windows多线程多任务设计初步(转)

    Windows多线程多任务设计初步 [前言:]当前流行的Windows操作系统,它能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程 ...

随机推荐

  1. how-to-build-c-static-libraries-boost

    http://tungchingkai.blogspot.jp/2016/11/how-to-build-c-static-libraries-boost.html How to build C++ ...

  2. 上传控件---淘宝kissy uploader+瀑布流显示

    介绍Uploader : Uploader 是由阿里集团前端工程师们发起创建的一个开源 JS 框架.它具备模块化.高扩展性.组件齐全,接口一致.自主开发.适合多种应用场景等特性. Uploader是非 ...

  3. 总结一下最近用到的技术(2)--JsonSchema和JsonSchemaValidator

    我们最早接触xml的时候会使用一个dtd文件去定义xml里可以有哪些元素和属性等,后来发展到xml schama(是一个xsd文件,在dtd的基础上提供了命名空间等更强大的功能) 现在,RESTful ...

  4. 把握这两点,抢占下一个电商风口|2016最新中国电商App排名&研究报告

    序言 电商,是随着中国互联网经济的持续发展所成长起来的.淘宝.京东这些电商从交易额和影响力上看都位列中国最为成功.最具话题性的互联网企业之中.尽管近几年中国经济有所放缓,但中国消费市场的增长速度仍有望 ...

  5. Sass::SyntaxError related to active_admin/mixins

    in active_admin.css.sass, change: @import "active_admin/mixins"; @import "active_admi ...

  6. 【CF653G】Move by Prime 组合数

    [CF653G]Move by Prime 题意:给你一个长度为n的数列$a_i$,你可以进行任意次操作:将其中一个数乘上或者除以一个质数.使得最终所有数相同,并使得操作数尽可能小.现在我们想要知道$ ...

  7. SVG学习笔录(二)

    一.svg动画SMIL SVG采用的是使用文本来定义图形,这种文档结构非常适合于创建动画.要改变图形的位置.大小和颜色,只需要调整相应的属性就可以了.事实上,SVG有为各种事件处理而专门设计的属性,甚 ...

  8. 【转载】纵观RTX51

    对于使用RTX51的具体好处可以在实践中去体会,就象会用了C51,就不想再用汇编了.用了RTX51,说不定就感到再也离不开它了. 1.RTX51是实时多任务操作系统RTX51是一种实时操作系统既目前在 ...

  9. PHP静态化(非伪静态化)

    什么是PHP静态化 PHP静态化的简单理解就是使网站生成页面以静态HTML的形式展现在访客面前,PHP静态化分纯静态化和伪静态化,两者的区别在于PHP生成静态页面的处理机制不同. 为什么要让网页静态化 ...

  10. CentOS 6U7分区大于2TB的磁盘以及挂载大于16TB分区磁盘的解决方案

    一.内容介绍1.问题描述1).问题一 CentOS 6.x 在格式化大于16TB的ext4分区时,会提示如下错误: mke2fs 1.41.12 (17-May-2010)mkfs.ext4: Siz ...