进程与线程基础

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

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

线程: 程序执行的最小单元。每个进程至少一个线程,进程是线程的容器。线程是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. 二叉树的实现(Java语言描述)

    实现二叉树   并先序遍历之. package 二叉树的实现; public class BinaryTree<T> { class Node { int value; // 该节点存储的 ...

  2. 使用CMake编译跨平台静态库

    在开始介绍如何使用CMake编译跨平台的静态库之前,先讲讲我在没有使用CMake之前所趟过的坑.因为很多开源的程序,比如png,都是自带编译脚本的.我们可以使用下列脚本来进行编译:   . / con ...

  3. 解决win764位安装pycrypto遇到unable to find vcvarsall.bat 问题

    今天安装pycrypto的库.安装中遇到一些问题,这里简单记录下来. 首先安装python,pycrypto是基于python的一个库. 第一种:搜索关键字pycrypto,找到pycrypto的官方 ...

  4. LeetCode 44 Wildcard Matching(字符串匹配问题)

    题目链接:https://leetcode.com/problems/wildcard-matching/?tab=Description   '?' Matches any single chara ...

  5. Artech的MVC4框架学习——第六章Model的验证

    第一Model验证旨在为通过Model绑定生成参数进行检验以确保用户输入数据的有效性(p318) 第二Model验证分两种:服务器端(三种解决方案 p256)和客户端(ajax\jQuery) 第三服 ...

  6. Artech的MVC4框架学习——第三章controller的激活

    第一当目标controller的名称通过URL路由被解析出来后,asp.net mvc利用 ControllerBuilder 注册 ControllerFactory ,根据名称实现对目标contr ...

  7. 使用spring提供的ReflectionUtils简化项目中反射代码的复杂性

    在项目中有时候我们会使用到反射的功能,如果使用最原始的方法来开发反射的功能的话肯能会比较复杂,需要处理一大堆异常以及访问权限等问题.spring中提供了ReflectionUtils 这个反射的工具类 ...

  8. C语言位操作--逻辑运算符组合

    假设读者熟悉普通代数与布尔代数,下面是部分常见的涉及到加法.减法与逻辑运算符的组合: a.        -x=~x+1 b.           =~(x-1) c.        ~x=-x-1 ...

  9. 【CF913F】Strongly Connected Tournament 概率神题

    [CF913F]Strongly Connected Tournament 题意:有n个人进行如下锦标赛: 1.所有人都和所有其他的人进行一场比赛,其中标号为i的人打赢标号为j的人(i<j)的概 ...

  10. ios atomic nonatomic区别

    atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作.         atomic 设置成员变量的@property属性时,默认为atomic,提供多线程安全 ...