线程类与线程池

一.线程类

》》函数

1.创建线程

void startThread(bool bSuspend = false)

2.停止线程

virtual void endThread() = 0

3.挂起线程

void suspendThread()

4.恢复线程

void resumeThread()

5.获取线程句柄

inline HANDLE GetHandle(){return m_hThread;}

6.线程的入口函数

static unsigned int __stdcall m_fnThread(void *ptr)

6.执行某些操作

virtual void run() = 0

》》数据

HANDLE m_hThread;

bool m_bSuspend;

// MyThread.h
#pragma once

#include "CommonHead.h"

class MyThread
{
public:
    MyThread(void);
    ~MyThread(void);

    void startThread(bool bSuspend = false); // 启动线程时是否为挂起状态
    virtual void endThread() = 0; // 纯虚函数

    void suspendThread(); // 挂起线程
    void resumeThread(); // 恢复线程

    inline HANDLE GetHandle() // 获取线程句柄
    {
        return m_hThread;
    }
protected:
    static unsigned int __stdcall m_fnThread(void *ptr); // 线程函数入口
    virtual DWORD run() = 0;
private:
    HANDLE m_hThread; // 线程句柄
};
// MyThread.cpp
#include <assert.h>

MyThread::MyThread(void)
    :m_hThread(INVALID_HANDLE_VALUE)
{
}

MyThread::~MyThread(void)
{
    if( INVALID_HANDLE_VALUE != m_hThread )
    {
        CloseHandle(m_hThread);
        m_hThread = INVALID_HANDLE_VALUE;
    }
}

// 线程函数入口
unsigned int __stdcall MyThread::m_fnThread(void *ptr)
{
    MyThread * pThread = (MyThread *)ptr;
    DWORD ret = 0;
    if(pThread)
    {
        ret = pThread->run();

        _endthread();
    }

    return ret;
}

// 启动线程时是否为挂起状态
void MyThread::startThread(bool bSuspend /*= false*/)
{
    assert( INVALID_HANDLE_VALUE == m_hThread);
    if( INVALID_HANDLE_VALUE == m_hThread )
    {
        unsigned threadID = 0;
        m_hThread = (HANDLE)_beginthreadex(NULL, 0, m_fnThread, (void *)this, (bSuspend ? CREATE_SUSPENDED : 0), &threadID);
    }
}

// 挂起线程
void MyThread::suspendThread()
{
    ::SuspendThread(m_hThread);
}

// 恢复线程
void MyThread::resumeThread()
{
    ::ResumeThread(m_hThread);
}

其中:

区分 CreateThrad 与 _beginthreadex 函数
HANDLEWINAPICreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes, // 线程内核对象的安全属性,一般传入NULL表示使用默认设置。
SIZE_TdwStackSize, // 线程栈空间大小。传入0表示使用默认大小(1MB)。
LPTHREAD_START_ROUTINElpStartAddress, // 新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
LPVOIDlpParameter, // 传给线程函数的参数。
DWORDdwCreationFlags, // 线程启动时是挂起还是运行状态.0 表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行
LPDWORDlpThreadId // 返回线程的ID号,传入NULL表示不需要返回该线程ID号。
);
配套线程等待函数
DWORDWINAPIWaitForSingleObject(
HANDLEhHandle, // 要等待的内核对象
DWORDdwMilliseconds // 最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入 INFINITE 表示无限等待。
);
返回值
在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED

unsigned long _beginthreadex(
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist, /* 这个就是传给线程函数的参数的指针 */
unsigned initflag,
unsigned *thrdaddr );

尽量使用_beginthreadex()来代替使用CreateThread()
_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。
事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。
因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。

二、线程池

需要上面的类

class MyThread;

头文件支持
#include <process.h>

》》函数

1.增加线程

void AddThread(MyThread *pthread, bool bSuspend)

2.批量开启线程

void BatchStartThread()

3.批量停止线程

void BatchStopThread()

4.释放所有线程

void Release()

5.设置自动释放

void SetAutoRelease(bool bVal)

》》变量

vector<MyThread *> m_threadList;

bool m_bAutoRelease;

// MyThreadPool.h
#pragma once

#include "MyThread.h"

class MyThreadPool
{
public:
    MyThreadPool(void);
    ~MyThreadPool(void);

    void AddThread(MyThread *thread, bool bSuspend = false); // 增加线程
    void BatchStopThread(); // 批量停止线程
    void BatchStartThread(); // 批量启动线程
    void Release(); // 释放全部线程
    void SetAutoRelease(bool bVal); // 是否自动释放线程
private:
    bool m_bAutoRelease; // 自动释放
    vector<MyThread *> m_threadList;
};
// MyThreadPool.cpp
#include "MyThreadPool.h"

MyThreadPool::MyThreadPool(void)
    :m_bAutoRelease(true)
{
}

MyThreadPool::~MyThreadPool(void)
{
    Release();
}

// 增加线程
void MyThreadPool::AddThread(MyThread *pthread, bool bSuspend /*= false*/)
{
    m_threadList.push_back(pthread);
    pthread->startThread(bSuspend);
}

// 批量停止线程
void MyThreadPool::BatchStopThread()
{
    MyThread * pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        pthread->endThread(); // 结束线程

        WaitForSingleObject(pthread->GetHandle(), INFINITE);

    }
}

// 批量启动线程
void MyThreadPool::BatchStartThread()
{
    MyThread * pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        pthread->resumeThread(); // 恢复线程
    }
}

// 释放全部线程
void MyThreadPool::Release()
{
    BatchStopThread();

    MyThread *pthread = NULL;
    int nSize = m_threadList.size();
    for(int i=0; i<nSize; ++i)
    {
        pthread = m_threadList[i];
        if(m_bAutoRelease)
            delete pthread;
    }

    m_threadList.clear();
}

// 是否自动释放线程
void MyThreadPool::SetAutoRelease(bool bVal)
{
    m_bAutoRelease = bVal;
}
时间: 2024-10-09 22:07:03

线程类与线程池的相关文章

Delphi 实现多线程编程的线程类 TThread

http://blog.csdn.net/henreash/article/details/3183119 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到, 但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了. 然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充. 线程本质上是进程中一段并发运行的代码. 一个进程至少有一个线程,即所谓的主线程. 同时还可以有多个

Delphi中线程类TThread 实现多线程编程

作者:Rogee出处:Http://Rogee.cnblogs.com/心得:BLOG是什么,它是一个记录学习过程的东西 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了.然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充. 线程本质上是进程中一段并发运行的代码.一个进程至少有一个线程,即所谓的主线程.同时还可以

Java多线程01(Thread类、线程创建、线程池)

Java多线程(Thread类.线程创建.线程池) 第一章 多线程 1.1 多线程介绍 1.1.1 基本概念 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程.一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序. 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 1.1.2 单线程程序 - 从入口m

juc下的并发工具类和线程池

工具类 CountDownLatch 利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了. package com.yjc.juc; import java.util.concurrent.CountDownLatch; public class CountDownLatchDemo { public static void main(String[] args) throws Interrupt

线程锁、线程池

一.线程(IO密集型工作多线程有用) 线程: 概述: 若一个文件从上到下顺序执行,则为串行执行,整个py文件实际上是一个主线程 若多线程,则可以并行执行,同一个时刻可以运行多个代码段 给每个client请求分配一个线程,则这些线程可以同时工作 多线程.多进程: 1.一个应用程序,可以有多进程和多线程:默认是单进程.单线程 2.单进程.多线程 : 多线程:IO操作(输入输出流,文件操作)有用,因为几乎不用cpu来调度,一般用多线程来提高并发 计算型操作,需要用到cpu调度执行,一般用多进程提高并发

线程基础:线程池(6)——基本使用(中)

(接上文:<线程基础:线程池(5)--基本使用(上)>) 3-4.JAVA主要线程池的继承结构 我们先来总结一下上文中讨论过的内容,首先就是JAVA中ThreadPoolExecutor类的继承结构.如下图所示: ThreadPoolExecutor:这个线程池就是我们这两篇文章中介绍的重点线程池实现.程序员可以通过这个线程池中的submit()方法或者execute()方法,执行所有实现了Runnable接口或者Callable接口的任务:ThreadPoolExecutor对于这些任务的执

[笔记][Java7并发编程实战手册]4.3 创建固定的线程执行器newFixedThreadPool线程池

[笔记][Java7并发编程实战手册]系列目录 简介 newFixedThreadPool(int nThreads, ThreadFactory threadFactory) 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程. newCachedThreadPool()创建的线程池的特性是:自动回收不使用的线程(终止并从缓存中移除那些已有 60 秒钟未被使用的线程),(在无可用线程的情况下)自动的为新来的task创

C#的线程类之Thread类以及对为什么设置线程优先级却不先执行这一问题本身的认识

1.C#对线程进行操作时,通过Thread类,可以对线程进行创建.挂起.恢复.休眠.终止及设置优先级. Thread类位于System.Threading命名空间下,该命名空间还包含一个ThreadPool类(允许用户使用系统提供的线程池)和一个Timer类(在线程池上执行回调方法) 在线程运行期间,不同的时刻会表现为不同的状态,但它总是处于由ThreadState定义的一个或多个状态中.用户可以通过使用ThreadPriority枚举为线程定义优先级,但不能保证操系统会接收该优先级 2.Thr

用ThreadLocal类实现线程安全的正确姿势

大家通常知道,ThreadLocal类可以帮助我们实现线程的安全性,这个类能使线程中的某个值与保存值的对象关联起来.ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回由当前执行线程在调用set时设置的最新值.从概念上看,我们把ThreadLocal<T>理解成一个包含了Map<Thread,T>的对象,其中Map的key用来标识不同的线程,而Map的value存放了特定该线程的某个值.但是ThreadL