c++相关知识-多线程

多线程相关

线程与进程

  • cpu:多个核心就能并行多个任务
  • 进程
    进程是程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。
  • 线程
    线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
  • 进程管着多个线程。

并发和并行

并行(parallellism)指的是多个任务在同一时刻同时在执行。
并发(concurrency)是指在一个时间段内,多个任务交替进行。虽然看起来像在同时执行,但其实是交替的。

多线程管理

  • 每个线程都需要一个入口函数,入口函数返回退出,该线程也会退出,主线程就是以main函数作为入口函数的线程。不太懂入口函数
  • detach和join
    1.detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。
    2.join方式,等待关联的线程完成,才会继续执行join()后的代码。
    3.在以detach的方式执行线程时,要将线程访问的局部数据复制到线程的空间(使用按值传递),一定要确保线程没有使用局部变量的引用或者指针,除非你能肯定该线程会在局部作用域结束前执行结束。
    4.调用类成员函数
    在这里插入图片描述
    5.转移线程的所有权
    在这里插入图片描述
    6.线程标识的获取
    线程的标识类型为std::thread::id,有两种方式获得到线程的id:1.通过thread的实例调用get_id()直接获取;2.在当前线程上调用this_thread::get_id()获取。
    9.2.6 线程暂停
    在这里插入图片描述7 异常情况下等待线程完成
    为了避免主线程出现异常时将子线程终结,就要保证子线程在函数退出前完成,即在函数退出前调用join()。
    方法一:异常捕获
void func() {
    thread t([]{
        cout << "hello C++ 11" << endl;
    });
 
    try
    {
        do_something_else();
    }
    catch (...)
    {
        t.join();
        throw;
    }
    t.join();
}

线程的同步与互斥

Windows下的
  • 临界区
    认为全局变量为共享资源,线程要访问共享资源得申请临界区。
#include "stdafx.h"
#include<windows.h>
#include<iostream>
using namespace std;
 
int number = 1; //定义全局变量
CRITICAL_SECTION Critical;      //声明临界区对象,初始化对象在main中
 
unsigned long __stdcall ThreadProc1(void* lp)//无符号长整型 
//以下是 __stdcall:
//表示函数的调用约定。调用约定是一组编译器约定,用于确定如何在调用函数时传递参数、以及谁(调用者还是被调用者)负责清除堆栈。
//在Windows平台上,__stdcall是一种常见的调用约定,通常用于Win32 API函数。
//对于线程处理函数,通常需要使用__stdcall调用约定,以满足Windows线程API(如CreateThread和_beginthreadex)的要求。
{
    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 是windows API用于创建线程函数的
    CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
 
    Sleep(10*1000);
 
    system("pause");
    return 0;
}
  • 事件
    我的理解:事件是一个对象,它有信号和非信号状态,一个线程可以等待对象有状态后再执行,,也可以设置这个状态,当一个等待线程被解除阻塞时(因为事件变为有信号状态),事件对象会立即重置为非信号状态(自动重置事件)
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//创建一个事件对象并获取其句柄
SetEvent(hEvent);//使用SetEvent函数将事件设置为有信号状态
DWORD result = WaitForSingleObject(hEvent, INFINITE);//线程可以使用WaitForSingleObject,函数等待事件对象变为有信号状态:
CloseHandle(hEvent);//最后,不要忘记在不再需要事件对象时使用CloseHandle函数关闭事件句柄:
  • 信号量
    我的理解:它和事件的区别与,信号量允许一定数量的线程访问。
    hSemaphore = CreateSemaphore(NULL, 1, 100, "sema");//创建
    WaitForSingleObject(hSemaphore, INFINITE);  //等待信号量为有信号状态
    ReleaseSemaphore(hSemaphore, 1, &count);//释放
c++下的锁
  • 互斥锁mutex ,还有很方便的std::lock_guard类(自动锁定锁),unique_guard类(可以不锁定,也可以在代码中锁定)
std::mutex mtx;
mtx.lock()
do_something...;    //共享的数据
mtx.unlock();
  • 条件锁(condition_variable ):等待通知
  • 自旋锁:互斥锁会让CPU去处理其他的任务,而自旋锁则会让CPU一直不断循环请求获取这个锁。
  • 原子操作
    原子操作(atomic operations)是指在多线程环境中,对共享数据的一系列操作,这些操作在执行过程中不会被其他线程打断。原子操作的主要目的是避免并发问题,如竞态条件(race conditions)和数据不一致。
    atomic类提供了原子操作
    例子:
    counter的原来的int型,改为atomic_int型就可以了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值