首页 > 系统相关 >【Linux】多线程_3

【Linux】多线程_3

时间:2024-07-13 22:56:28浏览次数:18  
标签:std 多线程 void 线程 Linux include testThread

文章目录


九、多线程

3. C++11中的多线程

Linux中是根据多线程库来实现多线程的,C++11也有自己的多线程,那它的多线程又是怎样的?我们来使用一些C++11的多线程。
Makefile

testThread: testThread.cc
	g++ -o $@ $^ -std=c++11
.PHONY: clean
clean:
	rm -f testThread

testThread.cc

#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;

void threadrun(int num)
{
    while (num)
    {
        cout << "I am thread, num : " << num << endl;
        sleep(1);
        --num;
    }
}

int main()
{
    thread t1(threadrun, 10);
    while (true)
    {
        cout << "I am main thread" << endl;
        sleep(1);
    }

    t1.join();
    
    return 0;
}

编译看看:
在这里插入图片描述
我们发现有问题(也可能是其他问题),这是怎么回事呢?其实是 C++11的多线程本质上是对原生线程的封装。所以同样需要链接 phread 动态库。
Makefile

testThread: testThread.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
	rm -f testThread

我们再试试:
在这里插入图片描述
确实大部分其编程语言的多线程都是对原生线程的封装,原因是为了可移植性。
我们在进程部分学过 非阻塞等待 ,进程在等待子进程退出时,可以执行其他任务,在线程这里,同样有这样的技术,叫做线程分离。我们要是不关注线程的结果,只需要线程把自己的任务完成,这种情况就可以将线程进行分离。
在这里插入图片描述
Makefile

testThread: testThread.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
	rm -f testThread

testThread.cc

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;

void* threadrun(void* args)
{
    string str = (const char*)args;
    int cnt = 5;
    while (true)
    {
        if (!(cnt--)) break;
        cout << "I am a new thread " << endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void*)"thread1");
    // 线程分离
    pthread_detach(tid);

    while (true)
    {
        cout << "I am the main thread " << endl;
        sleep(1);
    }

    return 0;
}

在这里插入图片描述

默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

joinable和分离是冲突的,一个线程不能既是joinable又是分离的。如果将线程分离了又对其join,就会出错。
线程分离底层依旧是属于进程,没有分开,线程分离只是一种状态,唯一的区别就是主线程不需要等待新线程。

4. 线程的简单封装

Makefile

testThread: testThread.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:
	rm -f testThread

Thread.hpp

#ifndef __THREAD_HPP__
#define __THREAD_HPP__

#include <iostream>
#include <pthread.h>
#include <string>
#include <functional>
#include <unistd.h>

// 线程命名空间
namespace ThreadModule
{
    // 线程函数模板
    template<typename T>
    using func_t = std::function<void(T&)>;

    // 线程模板
    template<typename T>
    class Thread
    {
    public:
        Thread(func_t<T> func, T data, const std::string& name = "none-name")
        :_func(func)
        ,_data(data)
        ,_threadname(name)
        ,_stop(true)
        {}

        void Excute()
        {
            _func(_data);
        }

        static void* threadtoutine(void* args)
        {
            Thread<T>* self = (Thread<T>*)args;
            self->Excute();
            return nullptr;
        }

        // 启动线程
        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, threadtoutine, this);
            if (n == 0)
            {
                _stop = false;
                return true;
            }
            else return false;
        }

        // 分离线程
        void Detach()
        {
            if (!_stop)
            {
                pthread_detach(_tid);
            }
        }

        // 等待线程结束
        void Join()
        {
            if (!_stop)
            {
                pthread_join(_tid, nullptr);
            }
        }

        std::string name()
        {
            return _threadname;
        }

        // 停止线程
        void Stop()
        {
            _stop = true;
        }

        ~Thread(){}
    private:
        pthread_t _tid;
        std::string _threadname;
        T _data;
        func_t<T> _func;
        bool _stop;
    };
}

#endif

testThread.cc

#include <iostream>
#include <vector>
#include "Thread.hpp"
using namespace ThreadModule;

const int num = 10;

// 线程执行的任务
void print(int& cnt)
{
    while (cnt)
    {
        std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;
        sleep(1);
    }
}

int main()
{
    // 创建多线程
    std::vector<Thread<int>> threads;
    // 创建num个线程,每个线程执行print函数
    for (int i = 0; i < num; ++i)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        threads.emplace_back(print, 10, name);
    }

    // 启动线程
    for (auto& thread : threads)
    {
        thread.Start();
    }

    // 等待线程结束
    for (auto& thread : threads)
    {
        thread.Join();
        std::cout << "wait thread done, thread name: " << thread.name() << std::endl;
    }

    return 0;
}

结果:
在这里插入图片描述


未完待续

标签:std,多线程,void,线程,Linux,include,testThread
From: https://blog.csdn.net/m0_69828905/article/details/140388188

相关文章

  • 在Linux中,apache有几种工作模式,分别介绍下其特点,并说明什么情况下采用不同的工作模式?
    在Linux中,Apache服务器支持多种工作模式,每种模式都有其特定的应用场景和优缺点。Apache的三种主要工作模式是:Prefork、Worker和Event。以下是对这三种工作模式的详细介绍及其适用场景:1.Prefork模式特点:非线程型、预派生:Prefork模式使用多个子进程来处理请求,每个子进程仅有一......
  • 在Linux中,如何编写shell脚本将当前目录下大于10K的文件转移到/tmp目录下?
    编写一个shell脚本来将当前目录下大于10K的文件转移到/tmp目录下,你可以遵循以下步骤:打开你的Linux终端。使用文本编辑器创建一个新的shell脚本文件,例如使用nano或vim:nanomove_large_files.sh在打开的编辑器中,编写以下脚本内容:#!/bin/bash#定义目标目录TARGET_DIR......
  • 在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
    在Linux中,FTP(FileTransferProtocol,文件传输协议)协议支持两种工作模式:主动模式(ActiveMode)和被动模式(PassiveMode)。这两种模式在数据传输的发起和连接建立的方式上存在显著差异。以下分别详细说明这两种模式的工作流程:一、主动模式(ActiveMode)建立控制连接:客户端首先通过TC......
  • 在Linux中,如何改IP、主机名、DNS?
    在Linux系统中,更改IP地址、主机名和DNS设置通常涉及到几个关键的配置文件和命令。具体步骤会根据你的Linux发行版有所不同,但这里我将以常见的CentOS/RHEL系统为例,说明这些操作的一般流程。1.更改IP地址检查当前的网络接口:ipaddrshow找到你要修改的网络接口配置文件。......
  • 在Linux中,如何添加路由?
    在Linux中,添加路由是一个常见的网络配置任务,可以通过多种方法实现。以下是详细的步骤和说明:一、使用route命令添加路由(临时路由)route命令是Linux中用于显示和操作IP路由表的工具。使用route命令添加的路由是临时的,即在系统重启或网络接口重启后路由将失效。1.添加到主机的路由......
  • Linux hwspinlock子系统(STM32MP157 HSEM)
    hwspinlock(硬件自旋锁)是Linux内核中的一个同步机制,它提供了一种在多核处理器系统中保护共享资源的方法。hwspinlock分为三部分:hwspinlockcore提供注册注销以及对hwspinlock获取和释放接口。hwspinlockController驱动。hwspinlockClient驱动,使用hwspinlock提供的同步机制......
  • Linux常用文件操作命令
    本章将和大家分享Linux常用的文件操作命令。废话不多说,下面我们直接进入主题。一、目录切换(cd命令)在Linux系统中,cd是一个用于切换当前工作目录的命令,它是"changedirectory"的缩写。基本用法如下所示:1、不带参数示例:cd或cd~如果cd命令后没有跟任何参数,它会将当前用户的......
  • Android C++系列:Linux常用函数和工具
    1.时间函数1.1文件访问时间#include<sys/types.h>#include<utime.h>intutime(constchar*name,conststructutimebuf*t);返回:若成功则为0,若出错则为-1如果times是一个空指针,则存取时间和修改时间两者都设置为当前时间;如果times是非空指针,则存取时......
  • Android C++系列:Linux进程间关系
    1.终端在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(ControllingTerminal),在前面文章我们说过,控制终端是保存在PCB中的信息,而我们知道fork会复制PCB中的信息,因此由Shell进程启动的其它进程的控制终端也是这个终端。默认情况......
  • Linux磁盘-格式化&挂载
    作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。Linux磁盘涉及到的命令不是很多,但是在实际运维中的作用却很大,因为Linux系统及业务都会承载到硬盘上。如果磁盘使用和配置不合理,可能会引起系统无法启......