C++——多线程

 

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, 1, 100, "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 = 1; //定义全局变量
CRITICAL_SECTION Critical;      //定义临界区句柄

unsigned long __stdcall ThreadProc1(void* lp)
{
    while (number < 100)
    {
        EnterCriticalSection(&Critical);//标识一个临界区。
        cout << "thread 1 :"<<number << endl;
        ++number;
        _sleep(100);
        LeaveCriticalSection(&Critical);//释放一个临界区
    }

    return 0;
}

unsigned long __stdcall ThreadProc2(void* lp)
{
    while (number < 100)
    {
        EnterCriticalSection(&Critical);
        cout << "thread 2 :"<<number << endl;
        ++number;
        _sleep(100);
        LeaveCriticalSection(&Critical);
    }

    return 0;
}

int main()
{
    InitializeCriticalSection(&Critical);   //初始化临界区对象

    CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

    Sleep(10*1000);

    system("pause");
    return 0;
}

 

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 = 1; //定义全局变量
HANDLE hEvent;  //定义事件句柄

unsigned long __stdcall ThreadProc1(void* lp)
{
    while (number < 100)
    {
        WaitForSingleObject(hEvent, INFINITE);  //等待对象为有信号状态
        cout << "thread 1 :"<<number << endl;
        ++number;
        _sleep(100);
        SetEvent(hEvent);//将事件对象置为有信号状态
    }

    return 0;
}

unsigned long __stdcall ThreadProc2(void* lp)
{
    while (number < 100)
    {
        WaitForSingleObject(hEvent, INFINITE);  //等待对象为有信号状态
        cout << "thread 2 :"<<number << endl;
        ++number;
        _sleep(100);
        SetEvent(hEvent);//将事件对象置为有信号状态
    }

    return 0;
}

int main()
{
    CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
    hEvent = CreateEvent(NULL, FALSE, TRUE, "event");

    Sleep(10*1000);

    system("pause");
    return 0;
}

 

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 = 1; //定义全局变量
HANDLE hSemaphore;  //定义信号量句柄

unsigned long __stdcall ThreadProc1(void* lp)
{
    long count;
    while (number < 100)
    {
        WaitForSingleObject(hSemaphore, INFINITE);  //等待信号量为有信号状态
        cout << "thread 1 :"<<number << endl;
        ++number;
        _sleep(100);
        ReleaseSemaphore(hSemaphore, 1, &count);
    }

    return 0;
}

unsigned long __stdcall ThreadProc2(void* lp)
{
    long count;
    while (number < 100)
    {
        WaitForSingleObject(hSemaphore, INFINITE);  //等待信号量为有信号状态
        cout << "thread 2 :"<<number << endl;
        ++number;
        _sleep(100);
        ReleaseSemaphore(hSemaphore, 1, &count);
    }

    return 0;
}

int main()
{
    hSemaphore = CreateSemaphore(NULL, 1, 100, "sema");

    CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

    Sleep(10*1000);

    system("pause");
    return 0;
}

 

 

4.互斥量/互锁

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

eg1:

#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std;

int number = 1; //定义全局变量
HANDLE hMutex;  //定义互斥对象句柄

unsigned long __stdcall ThreadProc1(void* lp)
{
    while (number < 100)
    {
        WaitForSingleObject(hMutex, INFINITE);
        cout << "thread 1 :"<<number << endl;
        ++number;
        _sleep(100);
        ReleaseMutex(hMutex);
    }

    return 0;
}

unsigned long __stdcall ThreadProc2(void* lp)
{
    while (number < 100)
    {
        WaitForSingleObject(hMutex, INFINITE);
        cout << "thread 2 :"<<number << endl;
        ++number;
        _sleep(100);
        ReleaseMutex(hMutex);
    }

    return 0;
}

int main()
{
    hMutex = CreateMutex(NULL, false, "mutex");     //创建互斥对象

    CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

    Sleep(10*1000);

    system("pause");
    return 0;
}

 

eg2:

#include <iostream>   
#include <windows.h>   
using namespace std;

HANDLE hMutex;

DWORD WINAPI Fun(LPVOID lpParamter)//线程定义
{
    while (1) {
        WaitForSingleObject(hMutex, INFINITE);//申请得到该资源:hMutex指定所申请的资源的句柄,INFINITE,表示如果没有申请到资源就一直等待该资源
        cout << "Fun display!" << endl;
        Sleep(1000);
        ReleaseMutex(hMutex);//该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了
    }
}

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

    return 0;
}

 


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

 

posted @ 2019-01-06 12:37  寒江小筑  阅读(1046)  评论(0编辑  收藏  举报