1.多进程和多线程:进程是一个总任务,一个进程可能包含多个线程。

2.并行并发:

  并发的关键是你有处理多个任务的能力,不一定要同时。

  并行的关键是你有同时处理多个任务的能力。

3.共享数据的管理和线程间的通信

1.同步

所谓同步,是指在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。

如果用对资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

2.互斥

所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。

如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

3.互锁机制解决多线程的同步问题:只允许一个线程拥有对共享资源的独占

参考:http://www.jizhuomi.com/software/287.html?utm_source=tuicool

在WIN32中,同步机制主要有以下几种: 
(1)事件(Event); 
(2)信号量(semaphore); 
(3)互斥量(mutex); 
(4)临界区(Critical section)。

InitializeCriticalSection(&Critical);               //初始化临界区对象
hEvent = CreateEvent(NULL, FALSE, TRUE, "event");
hSemaphore = CreateSemaphore(NULL, , , "sema");
hMutex = CreateMutex(NULL, false, "mutex"); //创建互斥对象

1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

2、互斥量:为协调共同对一个共享资源的单独访问而设计的。

3、信号量:为控制一个具有有限数量用户资源而设计。

4、事 件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

1. 互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使 用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。

2. 互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但 对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和 线程退出。

3. 通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根 据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数 器。

1.临界区和互斥量可是视为相同的类型,区别是临界区只能用于进程内,而互斥量可用于不同进程中不不同线程。两个都是将线程串行化,面对高并发和长代码,效率低

2.信号量:线程并行化。

1. CRITICAL_SECTION(临界区): 公厕管理人员每次允许一个人进入,直到他出去了,下一个人才可以进入。
2. Event(事件): 他告诉你公厕里面当前的状态。但是,你可以闯进去。他不会管你。要干什么取决于你。
3. Semaphore(信号量): 他允许公厕里面有N个人同时用,再多的人就必须排队。
4. mutex(互斥量): 厕所是属于他的。他用的时候,别人决不能进去。他不用的时候,得到他的允许,别人才能进去。他也可以选择让厕所空着。


原文:https://blog.csdn.net/liangtianmeng/article/details/81282486

应用:

一、并行方式的信号量在访问相同的一组资源时是最好的方法,因为它最大限度减少了系统调度线程的成本。

二、临界区和互斥量只应用于访问串行资源(例如使用全局计数器,系统参数访问和修改)。同一进程下的线程串行化时,只应该使用临界区

三、按指定的规则进行线程协调时使用事件。

1.临界区(Critical Section)

临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。

#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std; int number = ; //定义全局变量
CRITICAL_SECTION Critical; //定义临界区句柄 unsigned long __stdcall ThreadProc1(void* lp)
{
while (number < )
{
EnterCriticalSection(&Critical);//标识一个临界区。
cout << "thread 1 :"<<number << endl;
++number;
_sleep();
LeaveCriticalSection(&Critical);//释放一个临界区
} return ;
} unsigned long __stdcall ThreadProc2(void* lp)
{
while (number < )
{
EnterCriticalSection(&Critical);
cout << "thread 2 :"<<number << endl;
++number;
_sleep();
LeaveCriticalSection(&Critical);
} return ;
} int main()
{
InitializeCriticalSection(&Critical); //初始化临界区对象 CreateThread(NULL, , ThreadProc1, NULL, , NULL);
CreateThread(NULL, , ThreadProc2, NULL, , NULL); Sleep(*); system("pause");
return ;
}

2.事件(Event)

事件(Event)是WIN32提供的最灵活的线程间同步方式,事件可以处于激发状态(signaled or true)或未激发状态(unsignal or false)。根据状态变迁方式的不同,事件可分为两类:
(1)手动设置:这种对象只可能用程序手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。 //SetEvent把指定的事件对象设置为有信号状态,ResetEvent把指定的事件对象设置为无信号状态
(2)自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。

使用”事件”机制应注意以下事项:
(1)如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空间中的其它全局命名对象冲突;
(2)事件是否要自动恢复;
(3)事件的初始状态设置。

#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std; int number = ; //定义全局变量
HANDLE hEvent; //定义事件句柄 unsigned long __stdcall ThreadProc1(void* lp)
{
while (number < )
{
WaitForSingleObject(hEvent, INFINITE); //等待对象为有信号状态
cout << "thread 1 :"<<number << endl;
++number;
_sleep();
SetEvent(hEvent);//将事件对象置为有信号状态
} return ;
} unsigned long __stdcall ThreadProc2(void* lp)
{
while (number < )
{
WaitForSingleObject(hEvent, INFINITE); //等待对象为有信号状态
cout << "thread 2 :"<<number << endl;
++number;
_sleep();
SetEvent(hEvent);//将事件对象置为有信号状态
} return ;
} int main()
{
CreateThread(NULL, , ThreadProc1, NULL, , NULL);
CreateThread(NULL, , ThreadProc2, NULL, , NULL);
hEvent = CreateEvent(NULL, FALSE, TRUE, "event"); Sleep(*); system("pause");
return ;
}

3.信号量

信号量是维护0到指定最大值之间的同步对象。信号量状态在其计数大于0时是有信号的,而其计数是0时是无信号的。信号量对象在控制上可以支持有限数量共享资源的访问。

信号量的特点和用途可用下列几句话定义:
(1)如果当前资源的数量大于0,则信号量有效;
(2)如果当前资源数量是0,则信号量无效;
(3)系统决不允许当前资源的数量为负值;
(4)当前资源数量决不能大于最大资源数量。

//创建信号量
HANDLE CreateSemaphore (
 PSECURITY_ATTRIBUTE psa, //信号量的安全属性
  LONG lInitialCount, //开始时可供使用的资源数
  LONG lMaximumCount, //最大资源数
PCTSTR pszName); //信号量的名称 //释放信号量
BOOL WINAPI ReleaseSemaphore(
 HANDLE hSemaphore, //要增加的信号量句柄
 LONG lReleaseCount, //信号量的当前资源数增加lReleaseCount
 LPLONG lpPreviousCount //增加前的数值返回
); //打开信号量 
HANDLE OpenSemaphore (
 DWORD fdwAccess, //access
 BOOL bInherithandle, //如果允许子进程继承句柄,则设为TRUE
 PCTSTR pszName     //指要打开的对象的名字
);
#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std; int number = ; //定义全局变量
HANDLE hSemaphore; //定义信号量句柄 unsigned long __stdcall ThreadProc1(void* lp)
{
long count;
while (number < )
{
WaitForSingleObject(hSemaphore, INFINITE); //等待信号量为有信号状态
cout << "thread 1 :"<<number << endl;
++number;
_sleep();
ReleaseSemaphore(hSemaphore, , &count);
} return ;
} unsigned long __stdcall ThreadProc2(void* lp)
{
long count;
while (number < )
{
WaitForSingleObject(hSemaphore, INFINITE); //等待信号量为有信号状态
cout << "thread 2 :"<<number << endl;
++number;
_sleep();
ReleaseSemaphore(hSemaphore, , &count);
} return ;
} int main()
{
hSemaphore = CreateSemaphore(NULL, , , "sema"); CreateThread(NULL, , ThreadProc1, NULL, , NULL);
CreateThread(NULL, , ThreadProc2, NULL, , NULL); Sleep(*); system("pause");
return ;
}

4.互斥量/互锁

采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。

eg1:

#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std; int number = ; //定义全局变量
HANDLE hMutex; //定义互斥对象句柄 unsigned long __stdcall ThreadProc1(void* lp)
{
while (number < )
{
WaitForSingleObject(hMutex, INFINITE);
cout << "thread 1 :"<<number << endl;
++number;
_sleep();
ReleaseMutex(hMutex);
} return ;
} unsigned long __stdcall ThreadProc2(void* lp)
{
while (number < )
{
WaitForSingleObject(hMutex, INFINITE);
cout << "thread 2 :"<<number << endl;
++number;
_sleep();
ReleaseMutex(hMutex);
} return ;
} int main()
{
hMutex = CreateMutex(NULL, false, "mutex"); //创建互斥对象 CreateThread(NULL, , ThreadProc1, NULL, , NULL);
CreateThread(NULL, , ThreadProc2, NULL, , NULL); Sleep(*); system("pause");
return ;
}

eg2:

#include <iostream>
#include <windows.h>
using namespace std; HANDLE hMutex; DWORD WINAPI Fun(LPVOID lpParamter)//线程定义
{
while () {
WaitForSingleObject(hMutex, INFINITE);//申请得到该资源:hMutex指定所申请的资源的句柄,INFINITE,表示如果没有申请到资源就一直等待该资源
cout << "Fun display!" << endl;
Sleep();
ReleaseMutex(hMutex);//该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了
}
} int main()
{
HANDLE hThread = CreateThread(NULL, , Fun, NULL, , NULL);//开启线程
hMutex = CreateMutex(NULL, FALSE, L"screen"); //创造了一个名为screen并且归属于创建它的进程的资源
CloseHandle(hThread);
while () {
WaitForSingleObject(hMutex, INFINITE);//申请得到该资源:hMutex指定所申请的资源的句柄,INFINITE,表示如果没有申请到资源就一直等待该资源
cout << "main display!" << endl;
Sleep();
ReleaseMutex(hMutex);//该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了
} return ;
}

---------------------
作者:已不再少年
来源:CSDN
原文:https://blog.csdn.net/s_lisheng/article/details/74278765
版权声明:本文为博主原创文章,转载请附上博文链接!

C++——多线程的更多相关文章

  1. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  2. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  3. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  4. Java多线程

    一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程.   进程:进程 ...

  5. .NET基础拾遗(5)多线程开发基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  6. Java多线程基础——对象及变量并发访问

    在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...

  7. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  8. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  9. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

  10. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

随机推荐

  1. I.MX6 give su command more permission

    /************************************************************************************ * I.MX6 give s ...

  2. Linux 安全rm

    先将shell脚本放在某个全局路径下,如/usr/local/bin #!/bin/sh # safe rm # Don't remove the file, just move them to a ...

  3. rebar自定义template

    在开发过程中rebar自带模板建立项目,或多或少不能满足自己的开发需求.本人又是那种懒人,所以就要想办法偷懒.查看了priv模板 打造适合自己的项目模板.下面我简单的介绍整个模板的打造过程. 准备过程 ...

  4. 【英语】Bingo口语笔记(84) - 惊讶的表达

  5. centos下配置dns,gateway,ip

    centos网络配置实例 1,配置DNS vi /etc/resolv.conf 加入:   代码如下: nameserver 192.168.0.1 nameserver 8.8.8.8 names ...

  6. windows服务是如何被调用的?

    1.服务介绍 操作系统在启动的时候,会启动一些不需要用户交互的进程.这些进程被称为服务.当操作系统启动后它就自动被运行. 2.组成 服务程序.服务控制程序(SCP,service control pr ...

  7. DispatcherServlet的处理流程

    前言 上一篇介绍了SpringMVC的启动过程,DispatcherServlet作为一个前端控制器,分发处理http请求 1.DispatcherServlet流程图 具体流程: 1. 用户发请求- ...

  8. python中reload(module)的用法,以及错误提示

    1.Python2中可以和Python3中关于reload()用法的区别. Python2 中可以直接使用reload(module)重载模块.   Pyhton3中需要使用如下两种方式: 方式(1) ...

  9. 笔记:LIR2032 电池充电记录

    笔记:LIR2032 电池充电记录 LIR2032 电池是锂电池,形状和 CR2032 一样,只不过可以充电,材料是锂离子. 一个单颗的 LIR2032 电池容量只有 40mAH,容量很小. 那么就需 ...

  10. FastAdmin 社区 FAQ 帖子收集(F4NNIU 版 2018-08-12)

    FastAdmin 社区 FAQ 帖子收集 为什么Selectpage下拉列表在编辑时总是返回第一行的值? https://forum.fastadmin.net/thread/2399 根据条件值判 ...