进程与线程基础

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

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

线程: 程序执行的最小单元。每个进程至少一个线程,进程是线程的容器。线程是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. html2canvas - 解决办法之图片跨域导致的截图空白

    1. 后端支持:图片要是cdn上的地址,并且允许图片跨域,header头中设置应为 Access-Control-Allow-Origin:  * 2. 前端配置 var opts = { scale ...

  2. pip安装python包出现Cannot fetch index base URL http://pypi.python.org/simple/

    pipinstall***安装python包,出现 Cannot fetch index base URL  http://pypi.python.org/simple /错误提示或者直接安装不成功. ...

  3. 【转】Hudson插件Email-Ext邮件模板时间格式化的解决方法

    原文地址:http://www.cnblogs.com/haycco/archive/2012/03/20/3031397.html 最近因对Hudson版本进行了升级为2.2.0,所以各方面都在搞项 ...

  4. GPU对数据的操作不可累加

    我想当然的认为GPU处理数据时可以共同访问内存,所以对数据的操作是累加的. 事实证明:虽然GPU多个核可以访问同一块内存,但彼此之间没有依赖关系,它们对这块内存的作用无法累加. 先看代码: #incl ...

  5. Python 基础知识(一)

    1.Python简介 1.1.Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时 ...

  6. openstack 部署(Q版)-----glance镜像服务安装配置

    一.创建数据库 CREATE DATABASE glance; GRANT ALL PRIVILEGES ON glance.* TO '; GRANT ALL PRIVILEGES ON glanc ...

  7. org.springframework.dao.InvalidDataAccessApiUsageException

    org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read ...

  8. POJ--1050--To the Max(线性动规,最大子矩阵和)

    To the Max Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44723 Accepted: 23679 Descript ...

  9. hdu1754 I Hate It【线段树】

    很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.  这让很多学生很反感.  不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老 ...

  10. java 中常见的一些错误

    1.NosuchMethodError java 类中找不到该方法! 可能该类所在的同一个包下有一个相同的相同的类,然后那个类中没有我们所要调用的类. 解决方法:若那个类不需要,可以删除class! ...