Linux——多线程(五)

1.线程池

1.1初期框架

thread.hpp

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

namespace ThreadModule
{
    using func_t = std::function<void()>;

    class Thread
    {
    public:
        void Excute()
        {
            _func();
        }
    public:
        Thread(func_t func, std::string name="none-name")
            : _func(func), _threadname(name), _stop(true)
        {}
        static void *threadroutine(void *args) //注意:类成员函数,形参是有this指针的
        {
            Thread *self = static_cast<Thread *>(args);
            self->Excute();
            return nullptr;
        }
        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, threadroutine, this);
            if(!n)
            {
                _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;//线程tid
        std::string _threadname;//线程名字
        func_t _func;//线程所要执行的函数
        bool _stop;//判断线程是否停止
    };
}

 ThreadPool.hpp 

#include<vector>
#include<unistd.h>
#include<string>
#include<queue>
#include"Thread.hpp"

using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
public:
    ThreadPool(int threadnum=g_thread_num)//构造函数
        :_threadnum(threadnum)
        , _waitnum(0)
        , _isrunning(false)
    {
        pthread_mutex_init(&_mutex,nullptr);//初始化锁
        pthread_cond_init(&_cond,nullptr);//初始化条件变量
    }
    void Print()
    {
        while(true)
        {
            std::cout<<"我是一个线程"<<std::endl;
            sleep(1);
        }
    }
    void InitThreadPool()
	{
	    // 指向构建出所有的线程,并不启动
        for (int num = 0; num < _threadnum; num++)
	    {
	        std::string name = "thread-" + std::to_string(num + 1);
            _threads.emplace_back(Print,name);//线程处理函数是Print,注意这里有问题
	    }
	    _isrunning = true;
	}
    void Start()//启动线程池
    {
        for(auto &thread:_threads)
        {
            thread.Start();
            std::cout<<thread.name()<<"线程:启动成功"<<std::endl;
        }
    }



    void Wait()
    {
        for(auto &thread:_threads)
        {
            thread.Join();
        }
    }

    // bool Enqueue(const T &t)
    // {
    // }


    ~ThreadPool()//析构
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _threadnum;//线程的数量
    std::vector<Thread> _threads;//用vector来存线程
    std::queue<T> _task_queue;//任务队列

    pthread_mutex_t _mutex;//锁
	pthread_cond_t _cond;//条件变量
	int _waitnum;//有几个线程阻塞
    bool _isrunning;//判断线程池是否在运行
};

main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "threadpool.hpp"	
	
int main()
{
	std::unique_ptr<ThreadPool<int>> tp(new ThreadPool<int>()); 
	tp->InitThreadPool();
	tp->Start();
	sleep(5);

    tp->Wait();
    return 0;
}

 

 此时会报错:无效使用非静态成员函数...

主要原因是成员函数包含this指针而thread.hpp中线程所要执行函数的参数为空:using func_t = std::function<void()>;,导致参数类型不匹配

有两种解决方法

 方法一:在Print函数前面加上static

    static void Print()
    {
        while(true)
        {
            std::cout<<"我是一个线程"<<std::endl;
            sleep(1);
        }
    }

 

方法二:在初始化线程池时用bind绑定ThreadPool内部的Print方法,缺省地设置参数this,就是将this参数默认的绑定到Print方法上,这样一来就和thread.hpp中的参数匹配上了 

    void InitThreadPool()
	{
	    // 指向构建出所有的线程,并不启动
        for (int num = 0; num < _threadnum; num++)
	    {
	        std::string name = "thread-" + std::to_string(num + 1);
            //_threads.emplace_back(Print,name);//线程处理函数是Print
            _threads.emplace_back(std::bind(&ThreadPool::Print,this),name);
	    }
	    _isrunning = true;
	}

  也是成功运行

就算后面我们需要更改线程的参数
 那么也可以在初始化函数那里固定式的绑定参数了

不需要再去单独给线程设计参数对象了 

一个类的成员方法设计成另一个类的回调方法,常见的实现就是这种

类的成员方法也可以成为另一个类的回调方法,方便我们继续类级别的互相调用

 

1.2代码完善

 

接下来就是如何入队列以及我们的新线程应该做什么任务...

处理任务:每一个线程进来的时候都需要去任务队列中获取任务,所以我们首当其冲的就要对任务队列给它锁住

任务队列的加锁、解锁以及线程的等待与唤醒(条件变量)

private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadWakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }

 处理任务

    void HandlerTask(std::string name)//线程处理任务
    {
        while (true)
        {
            //加锁
            LockQueue();
            //任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住
            while(_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                ThreadSleep();
                _waitnum--;
            }
            //如果任务队列是空的,然后线程池又退出了,那么就没必要运行了
            if(_task_queue.empty() && !_isrunning)
            {
                UnlockQueue();
                std::cout<<name<<"quit..."<<std::endl;
                sleep(1);
                break;
            }
            //不论线程池有没有退出,走到这说明一定有任务 ->处理任务
            T t = _task_queue.front();
	        _task_queue.pop();
	        UnlockQueue();//解锁
            t();
        }
    }

 注意:这个任务是属于线程独占的任务,不能再任务队列的加锁、解锁之间处理

 入任务队列

如果线程阻塞等待的数量大于0,就唤醒一个线程

 

    bool Enqueue(const T &t)
    {
        bool ret = false;
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)
            {
                ThreadWakeup();
            }
            ret = true;
        }
        UnlockQueue();
        return ret;
    }

threadpool.hpp

任务还没写,所以t()先注释掉

#include<iostream>
#include<vector>
#include<unistd.h>
#include<string>
#include<queue>
#include"LockGuard.hpp"
#include"Thread.hpp"

using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadWakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
public:
    ThreadPool(int threadnum=g_thread_num)//构造函数
        :_threadnum(threadnum)
        , _waitnum(0)
        , _isrunning(false)
    {
        pthread_mutex_init(&_mutex,nullptr);//初始化锁
        pthread_cond_init(&_cond,nullptr);//初始化条件变量
    }
    // static void Print()
    // {
    //     while(true)
    //     {
    //         std::cout<<"我是一个线程"<<std::endl;
    //         sleep(1);
    //     }
    // }
    // void Print(std::string name)
    // {
    //     while(true)
    //     {
    //         std::cout<<"我是一个线程,线程名是"<<name<<std::endl;
    //         sleep(1);
    //     }
    // }
    void InitThreadPool()
	{
	    // 指向构建出所有的线程,并不启动
        for (int num = 0; num < _threadnum; num++)
	    {
	        std::string name = "thread-" + std::to_string(num + 1);
            //_threads.emplace_back(Print,name);//线程处理函数是Print
            //_threads.emplace_back(std::bind(&ThreadPool::Print,this,std::placeholders::_1),name);
	        _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);
	    }
	    _isrunning = true;
	}
    void Start()//启动线程池
    {
        for(auto &thread:_threads)
        {
            thread.Start();
            std::cout<<thread.name()<<"线程:启动成功"<<std::endl;
        }
    }

    void HandlerTask(std::string name)//线程处理任务
    {
        while (true)
        {
            //加锁
            LockQueue();
            //任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住
            while(_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                std::cout<<name<<"线程阻塞中..."<<std::endl;
                ThreadSleep();
                _waitnum--;
            }
            //如果任务队列是空的,然后线程池又退出了,那么就没必要运行了
            if(_task_queue.empty() && !_isrunning)
            {
                UnlockQueue();
                std::cout<<name<<"quit..."<<std::endl;
                sleep(1);
                break;
            }
            //不论线程池有没有退出,走到这说明一定有任务 ->处理任务
            T t = _task_queue.front();
	        _task_queue.pop();
	        UnlockQueue();//解锁
            //t();
        }
    }

    void Stop()
	{
	    LockQueue();
	    _isrunning = false;
	    ThreadWakeupAll();
	    UnlockQueue();        
	}


    void Wait()
    {
        for(auto &thread:_threads)
        {
            thread.Join();
        }
    }

    bool Enqueue(const T &t)
    {
        bool ret = false;
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)
            {
                ThreadWakeup();
            }
            ret = true;
        }
        UnlockQueue();
        return ret;
    }


    ~ThreadPool()//析构
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _threadnum;//线程的数量
    std::vector<Thread> _threads;//用vector来存线程
    std::queue<T> _task_queue;//任务队列

    pthread_mutex_t _mutex;//锁
	pthread_cond_t _cond;//条件变量
	int _waitnum;
    bool _isrunning;//判断线程池是否在运行
};

 main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "Task.hpp"
#include "threadpool.hpp"	
	
int main()
{
	std::unique_ptr<ThreadPool<int>> tp(new ThreadPool<int>()); 
	tp->InitThreadPool();
	tp->Start();
	sleep(2);

	tp->Stop();
    tp->Wait();
    return 0;
}

 

2.加上日志与任务

 LOG.hpp(日志)

#pragma once
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include"LockGuard.hpp"
bool gIsSave = false;
const std::string logname = "log.txt";

// 1. 日志是有等级的
enum Level
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};
void SaveFile(const std::string &filename, const std::string &message)
{
    std::ofstream out(filename, std::ios::app);
    if (!out.is_open())
    {
        return;
    }
    out << message;
    out.close();
}
std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";
    case WARNING:
        return "Warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "Unknown";
    }
}

std::string GetTimeString()
{
    time_t curr_time = time(nullptr);
    struct tm *format_time = localtime(&curr_time);
    if (format_time == nullptr)
        return "None";
    char time_buffer[1024];
    snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
             format_time->tm_year + 1900,
             format_time->tm_mon + 1,
             format_time->tm_mday,
             format_time->tm_hour,
             format_time->tm_min,
             format_time->tm_sec);
    return time_buffer;
}

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 日志是有格式的
// 日志等级 时间 代码所在的文件名/行数 日志的内容
void LogMessage(std::string filename, int line,bool issave,int level, const char *format, ...)
{

    std::string levelstr = LevelToString(level);
    std::string timestr = GetTimeString();
    pid_t selfid = getpid();

    char buffer[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer), format, arg);
    va_end(arg);

    std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
                          "[" + std::to_string(selfid) + "]" +
                          "[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";
    LockGuard lockguard(&lock);
    if (!issave)
    {
        std::cout << message;
    }
    else
    {
        SaveFile(logname, message);
    }
}
#define LOG(level, format, ...)                                                \
    do                                                                         \
    {                                                                          \
        LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \
    } while (0)

 LockGuard.hpp

#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__

#include <iostream>
#include <pthread.h>

class LockGuard
{
public:
    LockGuard(pthread_mutex_t *mutex):_mutex(mutex)
    {
        pthread_mutex_lock(_mutex); // 构造加锁
    }
    ~LockGuard()
    {
        pthread_mutex_unlock(_mutex);
    }
private:
    pthread_mutex_t *_mutex;
};

#endif

threadpool.hpp

#include<iostream>
#include<vector>
#include<unistd.h>
#include<string>
#include<queue>	
#include"LOG.hpp"
#include"LockGuard.hpp"
#include"Thread.hpp"

using namespace ThreadModule;
const int g_thread_num = 3;//默认线程数
// 线程池->一批线程,一批任务,有任务push、有任务pop,本质是: 生产消费模型
template <typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void ThreadWakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
public:
    ThreadPool(int threadnum=g_thread_num)//构造函数
        :_threadnum(threadnum)
        , _waitnum(0)
        , _isrunning(false)
    {
        pthread_mutex_init(&_mutex,nullptr);//初始化锁
        pthread_cond_init(&_cond,nullptr);//初始化条件变量
        LOG(INFO, "线程池构造成功");
    }
    // static void Print()
    // {
    //     while(true)
    //     {
    //         std::cout<<"我是一个线程"<<std::endl;
    //         sleep(1);
    //     }
    // }
    // void Print(std::string name)
    // {
    //     while(true)
    //     {
    //         std::cout<<"我是一个线程,线程名是"<<name<<std::endl;
    //         sleep(1);
    //     }
    // }
    void InitThreadPool()
	{
	    // 指向构建出所有的线程,并不启动
        for (int num = 0; num < _threadnum; num++)
	    {
	        std::string name = "thread-" + std::to_string(num + 1);
            //_threads.emplace_back(Print,name);//线程处理函数是Print
            //_threads.emplace_back(std::bind(&ThreadPool::Print,this,std::placeholders::_1),name);
	        _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);
            LOG(INFO, "线程 %s 初始化成功", name.c_str());
	    }
	    _isrunning = true;
	}
    void Start()//启动线程池
    {
        for(auto &thread:_threads)
        {
            thread.Start();
            std::cout<<thread.name()<<"线程:启动成功"<<std::endl;
        }
    }

    void HandlerTask(std::string name)//线程处理任务
    {
        LOG(INFO, "%s 正在运行...", name.c_str());
        while (true)
        {
            //加锁
            LockQueue();
            //任务队列中不一定有数据,如果任务队列为空且线程池在跑,那么就阻塞住
            while(_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                ThreadSleep();
                _waitnum--;
            }
            //如果任务队列是空的,然后线程池又退出了,那么就没必要运行了
            if(_task_queue.empty() && !_isrunning)
            {
                UnlockQueue();
                //std::cout<<name<<"quit..."<<std::endl;
                sleep(1);
                break;
            }
            //不论线程池有没有退出,走到这说明一定有任务 ->处理任务
            T t = _task_queue.front();
	        _task_queue.pop();
	        UnlockQueue();//解锁
            LOG(DEBUG, "%s 获得任务", name.c_str());
            t();
            LOG(DEBUG,"%s 处理任务中,结果是%s",name.c_str(), t.ResultToString().c_str());
        }
    }

    void Stop()
	{
	    LockQueue();
	    _isrunning = false;
	    ThreadWakeupAll();
	    UnlockQueue();        
	}


    void Wait()
    {
        for(auto &thread:_threads)
        {
            thread.Join();
            LOG(INFO, "%s 线程退出...", thread.name().c_str());
        }
    }

    bool Enqueue(const T &t)
    {
        bool ret = false;
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)
            {
                ThreadWakeup();
            }
            LOG(DEBUG, "任务入队列成功");
            ret = true;
        }
        UnlockQueue();
        return ret;
    }


    ~ThreadPool()//析构
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _threadnum;//线程的数量
    std::vector<Thread> _threads;//用vector来存线程
    std::queue<T> _task_queue;//任务队列

    pthread_mutex_t _mutex;//锁
	pthread_cond_t _cond;//条件变量
	int _waitnum;
    bool _isrunning;//判断线程池是否在运行
};

thread.hpp

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

namespace ThreadModule
{
    using func_t = std::function<void(std::string)>;

    class Thread
    {
    public:
        void Excute()
        {
            _func(_threadname);
        }
    public:
        Thread(func_t func, std::string name="none-name")
            : _func(func), _threadname(name), _stop(true)
        {}
        static void *threadroutine(void *args) // 类成员函数,形参是有this指针的!!
        {
            Thread *self = static_cast<Thread *>(args);
            self->Excute();
            return nullptr;
        }
        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, threadroutine, this);
            if(!n)
            {
                _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;//线程tid
        std::string _threadname;//线程名字
        func_t _func;//线程所要执行的函数
        bool _stop;//判断线程是否停止
    };
}

 

 main.cc

#include <iostream>	
#include <string>
#include <memory>
#include "LOG.hpp"
#include "threadpool.hpp"	
#include "Task.hpp"	
#include<ctime>

        
int main()
{
	srand(time(nullptr) ^ getpid() ^ pthread_self());
	std::unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>(5)); 
	tp->InitThreadPool();
	tp->Start();
	
	int tasknum=3;
	while(tasknum)
	{
		int a = rand() % 12 + 1;
		usleep(1000);
		int b = rand() % 4 + 1;
		Task t(a, b);
		LOG(INFO, "主线程推送任务: %s", t.DebugToString().c_str());
		tp->Enqueue(t);
		sleep(1);
		tasknum--;
	}

	tp->Stop();
    tp->Wait();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/788769.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python29 Tensorflow的基本知识和使用

1. TensorFlow TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google Brain 团队开发。它用于数据流图的计算&#xff0c;尤其擅长深度学习任务。在 TensorFlow 中&#xff0c;数据流图&#xff08;Data Flow Graph&#xff09;是其核心概念之一&#xff0c;它定义了计算…

Excel第28享:如何新建一个Excel表格

一、背景需求 小姑电话说&#xff1a;要新建一个表格&#xff0c;并实现将几个单元格进行合并的需求。 二、解决方案 1、在电脑桌面上空白地方&#xff0c;点击鼠标右键&#xff0c;在下拉的功能框中选择“XLS工作表”或“XLSX工作表”都可以&#xff0c;如下图所示。 之后&…

徒手绘制 Android 通用进度条

拖动条&#xff08;FlexSeekBar&#xff09;&#xff0c;在Android的各个地方都非常常用&#xff0c;本文旨在自研一套通用的进度条&#xff0c;非常适合车载App使用 样式如下&#xff1a; 使用示例 <!--默认用法--> <com.max.android.ui.seekbar.FlexSeekBarandroi…

Retrofit框架源码深度剖析【Android热门框架分析第二弹】

Android热门框架解析&#xff0c;你确定不来看看吗&#xff1f; OkHttp框架源码深度剖析【Android热门框架分析第一弹】 Retrofit框架源码深度剖析【Android热门框架分析第二弹】 什么是Retrofit&#xff1f; 准确来说&#xff0c;Retrofit 是一个 RESTful 的 HTTP 网络请求…

雷达视频采集卡 HPx-410

产品简介 雷达视频采集卡 HPx-410&#xff0c;应用于接入导航雷达数据&#xff0c;导航雷达视频&#xff0c;适用于JRC雷达、古野furuon雷达、Sperry雷达等多种型号的雷达。 HPx-410 可以接入导航雷达数据&#xff0c;引入导航雷达原始回波&#xff0c;然后将雷达视频采集到计…

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…

Python面试宝典第9题:买卖股票

题目 给定一个整型数组&#xff0c;它的第i个元素是一支给定股票第i天的价格。如果最多只允许完成一笔交易&#xff08;即买入和卖出一支股票一次&#xff09;&#xff0c;设计一个算法来计算你所能获取的最大利润。注意&#xff1a;你不能在买入股票前卖出股票。 示例 1&#…

设计模式之工厂模式(简单工厂、工厂方法、抽象工厂)

写在前面&#xff1a;本文是个人在学习设计模式时的所思所想&#xff0c;汇总了其他博主及自己的感悟思考&#xff0c;可能存在出入&#xff0c;请大家理性食用~~ 工厂模式 在工厂模式中&#xff0c;父类决定实例的生成方式&#xff0c;但并不决定所要生成的具体的类&#xf…

企业应对策略:全面防御.DevicData-P-xxxxxx勒索病毒

引言 在数字化时代&#xff0c;网络安全已成为不可忽视的重要议题。随着互联网的普及&#xff0c;各种网络威胁层出不穷&#xff0c;其中勒索病毒以其独特的攻击方式和巨大的破坏性&#xff0c;给个人用户和企业带来了严重的经济损失和数据安全风险。在众多勒索病毒中&#xff…

前端javascript中的排序算法之选择排序

选择排序&#xff08;Selection Sort&#xff09;基本思想&#xff1a; 是一种原址排序法&#xff1b; 将数组分为两个区间&#xff1a;左侧为已排序区间&#xff0c;右侧为未排序区间。每趟从未排序区间中选择一个值最小的元素&#xff0c;放到已排序区间的末尾&#xff0c;从…

LeetCode加油站(贪心算法/暴力,分析其时间和空间复杂度)

题目描述 一.原本暴力算法 最初的想法是&#xff1a;先比较gas数组和cost数组的大小&#xff0c;找到可以作为起始点的站点(因为如果你起始点的油还不能到达下一个站点&#xff0c;就不能作为起始点)。当找到过后&#xff0c;再去依次顺序跑一圈&#xff0c;如果剩余的油为负数…

11、Python之变量:看得见还是看不见

引言 在前面一篇关于Python变量的文章中&#xff0c;更多地结合对象的内存结构及字节码指令&#xff0c;来看不同代码针对不同的类型的对象的不同效果。 今天这篇文章中&#xff0c;想对新手在使用Python变量中&#xff0c;可能遇到的其他困惑&#xff0c;再展开来说一下。 大…

乐器培训课程报名小程序模板源码

模板介绍 一款实用的音乐课程&#xff0c;乐器培训&#xff0c;艺术类网页课程报名手机小程序模板下载。包含&#xff1a;主页、列表、个人中心、报名等模块。 图片演示 乐器培训课程报名小程序模板源码

《Windows API每日一练》9.13资源-鼠标位图和字符串

鼠标指针位图&#xff08;Mouse Cursor Bitmap&#xff09;是用于表示鼠标指针外观的图像。在 Windows 窗口编程中&#xff0c;可以使用自定义的鼠标指针位图来改变鼠标的外观&#xff0c;并提供更加个性化的用户体验。 ■以下是一些与鼠标指针位图相关的要点&#xff1a; ●…

九、C++11常用新特性—模板的优化

1.模板的右尖括号 在泛型编程种&#xff0c;模板实例化有一个非常繁琐的地方&#xff0c;那就是连续的两个右尖括号&#xff08;>>)会被编译器解析成右移操作&#xff0c;而不是模板参数表的结束&#xff0c;在C11以前需要在>>之间加上一个空格> >。C11之后…

中职网络安全Server2216

任务环境说明&#xff1a;✓ 服务器场景&#xff1a;Server2216&#xff08;开放链接&#xff09;✓ 用户名:root密码&#xff1a;1234561.黑客通过网络攻入本地服务器,通过特殊手段在系统中建立了多个异常进程找出启动异常进程的脚本&#xff0c;并将其绝对路径作为Flag值提交…

WindowsMac共享文件夹设置

共享文件夹设置 共享文件夹设置Windows系统设置步骤一&#xff1a;设置共享文件夹步骤二: 访问共享文件夹 Mac系统中设置共享文件夹步骤一&#xff1a;设置共享文件夹步骤二&#xff1a;访问共享文件夹 小贴士结论 共享文件夹设置 有时需要在多台电脑之间共享文件夹&#xff0…

学习嵌入式对于学历有要求吗?

学习嵌入式系统开发通常并不对学历有严格的要求&#xff0c;尤其是在技术行业中&#xff0c;实际的技能和经验往往比学历更为重要。我收集归类了一份嵌入式学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕…

【C++报错已解决】Multiple Definition of Symbol

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法&#xff1a;方法一&#xff1a;使用extern关键…

设计模式之Facade设计模式

Facade设计模式&#xff0c;也称为外观模式&#xff0c;是一种结构型设计模式&#xff0c;它主要用于为子系统中的一组接口提供一个统一的高层接口&#xff0c;从而使得子系统更加容易使用。以下是关于Facade设计模式的详细介绍&#xff1a; 一、定义 Facade模式为多个复杂的…