线程的概念:操作系统调度的最小单位。线程包含在进程中,是进程中实际运行的单位。一个进程中可以同时运行多个线程,每个线程可以执行不同的任务,这就是所谓的多线程。

内核:是操作系统最基本的部分,主要负责管理o系统资源

线程和进程的对比:

CPU调度和切换:线程的上下文切换比进程要快得多

线程更加廉价,启动速度更快,退出也快,对系统资源得冲击小

线程的终止:

线程函数返回:这是确保线程的所有资源被正确地清除的唯一办法。当线程函数返回时,如下情况将会发生:

  1. 在线程函数中创建的所有C++对象将通过它们的析构函数正确地撤销

  1. 操作系统将正确地释放线程的堆栈使用的内存;

  1. 系统将线程的退出代码设置为线程函数的返回值:

  1. 系统递减线程内核对象的引用计数

创建一个线程使用到的函数:

1.CreateThread函数:创建一个线程,函数原型

HANDLE CreateThread([in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,[in]            SIZE_T                  dwStackSize,[in]            LPTHREAD_START_ROUTINE  lpStartAddress,[in, optional]  __drv_aliasesMem LPVOID lpParameter,[in]            DWORD                   dwCreationFlags,[out, optional] LPDWORD                 lpThreadId
);

参数1:指向 SECURITY_ATTRIBUTES 结构的指针,该结构确定返回的句柄是否可以由子进程继承。 如果 lpThreadAttributes 为 NULL,则无法继承句柄

参数2:堆栈的初始大小(以字节为单位)。 系统将此值舍入到最近的页面。 如果此参数为零,新线程将使用可执行文件的默认大小 参数3:指向由线程执行的应用程序定义函数的指针。 此指针表示线程的起始地址 参数4:指向要传递给线程的变量的指针 参数5:控制线程创建的标志

返回值:会返回线程句柄

2.ExitThread函数:结束调用线程,函数原型

void ExitThread([in] DWORD dwExitCode
);

可以通过在线程中调用ExitThread函数,来强制终止自身线程的运行

该函数将终止自身线程的运行,,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源 (如C++对象)将不被正确地撤销

3.SuspendThread函数:挂起指定线程,函数原型

DWORD SuspendThread([in] HANDLE hThread
);

参数:对应线程的句柄

4.ResumeThread函数:递减线程的挂起计数。 当暂停计数递减为零时,将恢复线程的执行,就是恢复被挂起的线程,函数原型

DWORD ResumeThread([in] HANDLE hThread
);

参数:要重启的线程的句柄

返回值:如果函数成功,则返回值为线程的上一个挂起计数。如果函数失败,则返回值 (DWORD) -1。 要获得更多的错误信息,请调用 GetLastError

函数使用实例:

#define _CRT_SECURE_NO_WARNINGS#include<iostream>
#include<windows.h>
using namespace std;
//回调函数
DWORD WINAPI ThreadProc(PVOID lp)
{cout << "子线程" << endl;Sleep(1000);cout << "子线程2" << endl;return 0;
}int main()
{//该函数会返回一个句柄HANDLE hThread = CreateThread(NULL, 0, ThreadProc, 0, CREATE_SUSPENDED, 0);//参数4设置了线程挂起,不会执行子线程SuspendThread(hThread);//手动挂起ResumeThread(hThread);//把子线程恢复cout << "主线程" << endl;Sleep(1500);cout << "主线程2" << endl;CloseHandle(hThread);return 0;
}

5.InterlockedIncrement函数:将 (作为原子操作的指定 32 位变量的值增加一) 递增。若要对 64 位值进行操作,请使用 InterlockedIncrement64 函数。函数原型

LONG InterlockedIncrement([in, out] LONG volatile *Addend
);

参数:变量的地址

返回值:返回函数的递增值

临界区:临界区是一段连续的代码区域,它要求在执行前获得对某些共享数据的独占的访问权。如果一个进程中的所有线程中访问这些共享数据的代码都放在临界区中,就能够实现对该共享数据的同步访问。临界区只能用于同步单个进程中的线程

结构体 CRITICAL_SECTION 是创建临界区的对象,

6. InitializeCriticalSection函数:初始化关键节对象,也就是初始化临近区对象,函数原型

void InitializeCriticalSection([out] LPCRITICAL_SECTION lpCriticalSection
);

参数:指向关键节对象的指针,也就是临界区的地址

返回值:没有返回值

7. EnterCriticalSection函数:等待指定关键部分对象的所有权,等待临近区,函数原型

void EnterCriticalSection([in, out] LPCRITICAL_SECTION lpCriticalSection
);

参数:临界区地址

返回值:没有返回值

8. LeaveCriticalSection函数:释放指定关键节对象的所有权,释放临界区所有权,函数原型

void LeaveCriticalSection([in, out] LPCRITICAL_SECTION lpCriticalSection
);

参数:临界区地址

返回值:没有返回值

内核对象:常用的内核对象有互斥变量、信号量和事件,其他的还包括文件、控制台输入、文件变化通知、可等待的计时器

每一个内核对象在任何时候都处于两种状态之一: 信号态 (signaled) 和无信号态(nonsignaled)

互斥变量:通俗讲就是锁,类似于临界区,但它能够同步多个进程间的数据访问

9. CreateMutex函数:创建或打开命名或未命名的互斥对象,就是创建互斥变量,函数原型

HANDLE CreateMutexW([in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,[in]           BOOL                  bInitialOwner,[in, optional] LPCWSTR               lpName
);

参数1:指向 SECURITY_ATTRIBUTES 结构的指针。 如果此参数为 NULL,则子进程无法继承句柄

参数2:如果此值为 TRUE ,并且调用方创建了互斥体,则调用线程获取互斥体对象的初始所有权。 否则,调用线程不会获取互斥体的所有权

参数3:互斥体对象的名称

返回值:如果函数成功,则返回值是新创建的互斥体对象的句柄,否则返回NULL

10. WaitForSingleObject函数:等待指定对象处于信号状态或超时间隔已过,也就是等待有信号的互斥变量或者是事件,获取对象的所有权,函数原型

DWORD WaitForSingleObject([in] HANDLE hHandle,[in] DWORD  dwMilliseconds
);

参数1:对象的句柄

参数2:超时间隔,为 INFINITE,则仅当发出对象信号时,该函数才会返回

返回值:如果函数成功,则返回值指示导致函数返回的事件

11. ReleaseMutex函数:释放指定互斥对象的所有权,需要和WaitForSingleObject函数联合使用,函数原型

BOOL ReleaseMutex([in] HANDLE hMutex
);

参数1:互斥对象的句柄

返回值:如果该函数成功,则返回值为非零值,如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError

12. SetEvent函数:将指定的事件对象设置为非对齐状态,释放事件所有权,函数原型

BOOL ResetEvent([in] HANDLE hEvent
);

参数:事件对象的句柄

返回值:如果该函数成功,则返回值为非零值。如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError

函数使用实例:

#define _CRT_SECURE_NO_WARNINGS#include<iostream>
#include<windows.h>
using namespace std;//原子锁
unsigned int g;
//临界区
CRITICAL_SECTION g_sec;
//线程锁
HANDLE hmutex;
//事件
HANDLE hEvent;//回调函数
DWORD WINAPI ThreadProc(PVOID lp)
{for (int i = 0; i < 1000000; i++){//InterlockedIncrement(&g);//以原子方式加1,相当于给变量加锁进入临界区//EnterCriticalSection(&g_sec);//g++;//LeaveCriticalSection(&g_sec);//WaitForSingleObject(hmutex, INFINITE);//等待锁变成有信号//g++;//ReleaseMutex(hmutex);//把锁置为无信号WaitForSingleObject(hEvent, INFINITE);//等待有信号的事件g++;SetEvent(hEvent);//把事件置为无信号}return 0;
}int main()
{//初始化临界区对象InitializeCriticalSection(&g_sec);//创建锁hmutex = CreateMutex(NULL, FALSE, NULL);//创建事件对象hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);HANDLE hThread = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);for (int j = 0; j < 1000000; j++){//InterlockedIncrement(&g);进入临界区//EnterCriticalSection(&g_sec);//g++;//LeaveCriticalSection(&g_sec);//WaitForSingleObject(hmutex, INFINITE);//等待锁变成有信号//g++;//ReleaseMutex(hmutex);//把锁置为无信号WaitForSingleObject(hEvent, INFINITE);//等待锁变成有信号g++;SetEvent(hEvent);//把锁置为无信号}WaitForSingleObject(hThread, INFINITE);//等待线程printf("%d", g);CloseHandle(hThread);CloseHandle(hmutex);DeleteCriticalSection(&g_sec);//释放临界区return 0;
}

线程间的通信

  1. 使用全局变量进行通信

  1. 参数传递方式

  1. 消息传递方式

进程概念:

狭义定义:进程是正在运行的程序的实例

广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元

创建状态:进程在创建时需要申请一个空白PCB (进程控制块),向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态

就绪状态: 进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行

执行状态: 进程处于就绪状态被调度后,进程进入执行状态

阻寒状态:正在执行的进程由于某些事件 (I/O请求,申请缓存区失败) 而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用

终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行

进程的同步与互斥:

同步:为了完成某个任务而建立的两个或多个进程,这些进程为了需要在某些位置上协调它们的工作次序而等待传递信息所产生的制约关系。进程间的制约关系就是源于它们之间的相互合作

互斥:当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界区资源的进程退出临界区以后才允许进入临界区,访问资源。注意,这里的一个并非卡死就一次只能一个进程访问临界资源。当信号量个数大于1的时候,一次可以有多个进程同时访问临界资源。前文的互斥定义只是最原始的定义

同步准则:

  1. 空闲让进:临界区(每个进程中访问临界资源的那段代码称为临界区) 空闲时,应该允许某个进程立即进入临界区访问临界资源

  1. 忙则等待:当临界区进程访问数达到访问上限时,其他试图进入临界区的进程应该等待

  1. 有限等待:应该避免进程--直等待永远进入不了临界D的情况

  1. 让权等待:“权”即CPU使用权,当进程不能进入临界区的时候,应该放弃使用CPU,进入等待队列,而不是"忙等待”

进程中使用到的函数:

CreateProcess函数:创建新的进程及其主线程,函数原型

BOOL CreateProcessW([in, optional]      LPCWSTR               lpApplicationName,[in, out, optional] LPWSTR                lpCommandLine,[in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,[in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,[in]                BOOL                  bInheritHandles,[in]                DWORD                 dwCreationFlags,[in, optional]      LPVOID                lpEnvironment,[in, optional]      LPCWSTR               lpCurrentDirectory,[in]                LPSTARTUPINFOW        lpStartupInfo,[out]               LPPROCESS_INFORMATION lpProcessInformation
);

参数1:要执行的模块的名称

参数2:要执行的命令行

参数3:指向 SECURITY_ATTRIBUTES 结构的指针,该结构确定返回的句柄是否可由子进程继承到新进程对象。 如果 lpProcessAttributes 为 NULL,则无法继承句柄

参数4:指向 SECURITY_ATTRIBUTES 结构的指针,该结构确定新线程对象的返回句柄是否可以由子进程继承。 如果 lpThreadAttributes 为 NULL,则无法继承句柄

参数5:如果此参数为 TRUE,则调用过程中的每个可继承句柄都由新进程继承。 如果参数为 FALSE,则不会继承句柄

参数6:控制优先级类和创建进程的标志

参数7:指向新进程的环境块的指针。 如果此参数为 NULL,则新进程使用调用进程的环境

参数8:进程当前目录的完整路径。 字符串还可以指定 UNC 路径

参数9:指向 STARTUPINFO 或 STARTUPINFOEX 结构的指针

参数10:指向接收有关新进程的标识信息的 PROCESS_INFORMATION 结构的指针

代码实例:

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<windows.h>int main()
{TCHAR commandline[] = L"C:\\Users\\君莫笑\\AppData\\Local\\Mozilla Firefox\\firefox.exe";_STARTUPINFOW startinfo = { sizeof(_STARTUPINFOW) };//_PROCESS_INFORMATION processInfo;//参数10,进程信息的结构体//创建进程bool ret = CreateProcess(NULL,//不指定可执行文件的文件名commandline,//命令行参数NULL,//默认进程安全性NULL,//默认线程安全性FALSE,//指定当前进程的句柄是否被子进程继承0,//指定附加的、用来控制优先类和进程的创建的标志NULL, //使用当前进程的环境变量NULL,//使用当前进程的驱动和目录&startinfo,//指定一个用于决定新进程的主窗体如何显示的STARTUPINEO的结构体&processInfo//进程信息结构体);if (!ret){printf("创建进程失败\n");return 0;}else{printf("创建进程的ID:%d\n", processInfo.dwProcessId);printf("创建的主线程ID:%d\n", processInfo.dwThreadId);WaitForSingleObject(processInfo.hProcess, INFINITE);//等待进程句柄CloseHandle(processInfo.hProcess);CloseHandle(processInfo.hThread);}return 0;
}

进程间的通信:

四种方式:

无名管道 (pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系

命名管道 (named pipe)I: 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信

消息队列 (message queue): 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点

互斥量

共享内存(shared memory): 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信

使用共享内存通信使用到的函数:

CreateFileMapping函数:为指定文件创建或打开命名或未命名的文件映射对象,也就是创建一个映射内存的句柄,函数原型

HANDLE CreateFileMappingW([in]           HANDLE                hFile,[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,[in]           DWORD                 flProtect,[in]           DWORD                 dwMaximumSizeHigh,[in]           DWORD                 dwMaximumSizeLow,[in, optional] LPCWSTR               lpName
);

参数1:要从中创建文件映射对象的文件的句柄

参数2:指向 SECURITY_ATTRIBUTES 结构的指针,该结构确定返回的句柄是否可以由子进程继承

参数3:指定文件映射对象的页面保护,设置权限

参数4:文件映射对象的最大大小的高阶 DWORD

参数5:文件映射对象的名称

返回值:如果函数成功,则返回值是新创建的文件映射对象的句柄,如果函数失败,则返回值为 NULL

MapViewOfFile函数:将文件映射的视图映射到调用进程的地址空间,创建存储内容的缓冲空间,函数原型

LPVOID MapViewOfFile([in] HANDLE hFileMappingObject,[in] DWORD  dwDesiredAccess,[in] DWORD  dwFileOffsetHigh,[in] DWORD  dwFileOffsetLow,[in] SIZE_T dwNumberOfBytesToMap
);

参数1:文件映射对象的句柄

参数2:对文件映射对象的访问类型,用于确定页面的页面保护

参数3:视图开始位置的文件偏移量的高顺序 DWORD

参数4:要开始视图的文件偏移量低序 DWORD

参数5:要映射到视图的文件映射的字节数

返回值:如果函数成功,则返回值为映射视图的起始地址。如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError

UnmapViewOfFile函数:从调用进程的地址空间取消映射文件的映射视图,关闭由MapViewOfFile创建出来的缓存空间,函数原型

BOOL UnmapViewOfFile([in] LPCVOID lpBaseAddress
);

参数:指向要取消映射的文件的映射视图基址的指针

返回值:如果该函数成功,则返回值为非零值。如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError

函数使用实例:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include<windows.h>int main()
{//创建共享文件句柄HANDLE hmap = CreateFileMapping(NULL,//物理文件句柄NULL,//默认映射文件的安全级别PAGE_READWRITE,//访问权限0,//高位128,//低位TEXT("fileMap")//共享内存名);//创建映射区char* buf = (char*)MapViewOfFile(hmap, FILE_MAP_ALL_ACCESS, 0, 0, 128);gets_s(buf, 128);while (1);UnmapViewOfFile(buf);//关闭缓冲区CloseHandle(hmap);//关闭句柄return 0;
}

c/c++ 线程进程相关推荐

  1. 打开线程 | 进程 | 协程的大门

    不知从几何起,可能是大三那年的操作系统考试,也可能是刚经历完的秋招,这些概念总是迷迷糊糊,可能自己回答的和其他人的答复也差不多,并没有什么亮点,通常都会以:「我们换个题」的方式结束,有时候也挺尴尬的. ...

  2. linux 线程 进程经典文章

    进程是程 序在计算机上的一次执行活动.当你运行一个程序,你就启动了一个进程.显然,程序是 死的(静态的),进程是活的(动态的).进程可以分为系统进程和用户进程.凡是用于完成操作系统的各种功能的进程就是 ...

  3. PHP 会话 线程 进程,接上节我们来了解了解多进程的一些基础进程 / 线程 / 多进程 / 父进程 / 子进程 / 会话 / 控制终端等...

    多进程的一些基础 定义 进程/父进程/子进程 进程是资源调度和分配的一个独立单元 进程是由线程组成 即等于 一个进程 = 一个线程. 进程是由另一个进程创建 (系统进程 init进程除外) 所以会出现 ...

  4. Python的线程/进程间通讯对象分析

    2019独角兽企业重金招聘Python工程师标准>>> Python提供了一系列的对象支持线程/进程间的通讯: Lock RLock Condition Semaphone Boun ...

  5. python结束进程树_【python爬虫】线程进程

    关注:程序运行速度---->主要是由cpu(大脑)来决定. 想要提高程序的运行速度----->提高cpu利用率. 提高cpu的利用率由两种途径: 1.让cpu不休息.cpu每时每刻都在处理 ...

  6. python的线程如何启用和结束_python线程进程

    操作系统 一 为什么要有操作系统? 现代计算机系统是由一个或者多个处理器,主存,磁盘,打印机,键盘,鼠标显示器,网络接口以及各种其他输入 输出设备组成的复杂系统,每位程序员不可能掌握所有系统实现的细节 ...

  7. 【多线程】线程与进程、以及线程进程的调度

    在了解多线程之前,首先要区分线程和进程的概念与区别,我目前只了解到Java的JVM中与操作系统联系中的线程和进程,在了解线程与进程之前,首先要初步了解电脑中的操作系统的地位和作用. 冯诺依曼体系 计算 ...

  8. linux和Windows线程进程的区别

    1.linux线程进程 linux内核中,进程是用一个task_struct的结构体描述的,也就是进程描述符,里面包含了进程id.进程的地址空间.进程打开的文件信息.挂起的信号.进程的状态等等信息. ...

  9. android线程安全ppt,线程进程安全.ppt

    线程进程安全.ppt 第三章 线程 进程安全 进程和线程是两个范围不同的概念 进程是程序在计算机上的一次执行活动 运行一个程序 相当于启动了一个进程 进程是操作系统进行资源分配的单位 通俗地讲 是一个 ...

  10. 服务端的网络并发,详细解读网络io与线程进程的关系

    服务端的网络并发,详细解读网络io与线程进程的关系丨后端开发丨C/C++Linux服务器开发丨网络编程丨epoll的实现丨网络编程 视频讲解如下,点击观看: 服务端的网络并发,详细解读网络io与线程进 ...

最新文章

  1. repo入门和基本用法
  2. 深入浅出NIO之Channel、Buffer
  3. IO流以及他们的种类区别 序列化反序列化 如何实现
  4. InfluxData【环境搭建 01】时序数据库 InfluxDB 最新版本安装启动验证(在线安装+离线安装及各版本下载地址)
  5. Apollo进阶课程 ⑧ | 高精地图的格式规范
  6. Linux下ip route、ip rule、iptables的关系(转
  7. 运用cnn实现手写体(mnist)数字识别_实现 MNIST 手写数字识别
  8. java编程50题和解释_最新JAVA编程题全集(50题及答案)29515
  9. 人脸识别 java_基于Java实现人脸识别功能(附源码)
  10. 插桩 java_“插桩”式技术
  11. 基于51单片机机械臂控制系统
  12. 从阿里一面谈面试需要准备什么
  13. 中国移动“梧桐杯”大数据应用创新大赛强势来袭三大赛道再续辉煌
  14. 如何查看Navicat已保存数据库连接的密码
  15. Net Core WebApi自定义拦截特性简单实现
  16. 瑞星2007----免费升级法。
  17. vue3的撤销与重做
  18. Excel VBA高级编程 - 根据关键字自动搜索,自动生成下拉菜单
  19. 入门pandas—数据替换
  20. 基于MAX31865的温度控制系统

热门文章

  1. python设置时间过期改变状态_将Python程序设置为在特定天数后过期
  2. 网站更换服务器对于SEO有哪些影响?
  3. C++设计模式——状态模式
  4. 关于认知力的学习总结
  5. HTML的基础入门,快来看看吧~
  6. 考研作文重点框架、句子、词汇总结
  7. 五分钟理解主存储器的基本组成结构
  8. 03基础自绘-13滑动选择-tumbler
  9. 史上最简单的spark系列教程 | 完结
  10. pipeline的相关解释(instruction pipeline)