zoukankan      html  css  js  c++  java
  • C++多线程2.beginthread

    C++ 多线程2 beginthread 启动线程知识 20131021

    Reference: http://blog.csdn.net/laoyang360/article/details/7720656

    前言:

             之前曾经使用过WINAPI创建线程并且启动的知识,还有线程之间同步的知识,这里讲解一下使用__beginthread的原理和机制。

    1._beginthread 简单的介绍

             如果我们编写的是C++的程序,不应该使用CreateThread WINAPI接口去创建线程,而是应该使用Visual C++运行库函数_beginthread,退出线程的时候应该使用_endthread。因为_beginthreaex和_endthreadex是CRT的线程函数,所以必须注意编译选项runtimelibrary,使用的是MT或者是MTD(MultiThreaded,debug Multithread);_beginthread函数的参数列表和CreateThread的参数列表完全相同,但是参数名称和类型不是完全的相同。因为Microsoft的C/C++运行库的开的小组认为C/C++运行期函数不应该对Windows数据类型有任何的依赖。

             每一个线程都会获得由C/C++运行期库的堆栈分配自己的tiddata内存结构;传递给_beginthreadex的线程函数的地址保存在tiddata内存数据块,传递给该函数的参数也保存在该数据块中;_beginthreadex确实从内部调用CreateThread函数,因为这是创建线程早OS层面上的唯一的方法;当调用CreateThread函数的时候,他会被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新的线程,还有传递给线程函数的从哪回溯是tiddata结构而不是pvParam的地址;如果一切顺利的话,就会像CreateThread那样返回线程句柄,任何操作失败就会返回NULL。

             总的来说就是_beginthreadex在内部调用CreateThread函数,在调用之前_beginthreadex做了很多的工作,从而比CreateThread更加安全.

    #include <iostream>

    #include <string>

    #include <process.h>

    #include <Windows.h>

    using namespace std;

     

    class ThreadX{

    private:

        int loopStart;

        int loopEnd;

        int dispFrequency;

     

    public:

        string threadName;

     

        ThreadX(int startVal, int endVal, int frequency){

            this->loopStart = startVal;

            this->loopEnd = endVal;

            this->dispFrequency = frequency;

        }

        static unsigned __stdcall ThreadStaticEntryPoint(void * pThis){

            ThreadX* pThX = (ThreadX*) pThis;

            pThX->ThreadEntryPoint();

            return 1;

        }

        void ThreadEntryPoint(){

            for (int i = loopStart; i <= loopEnd; i++){

                cout << threadName << " i = " << i << endl;

                Sleep(100);

            }

        }

    };

     

    int main(){

        ThreadX * pThX = new ThreadX(0, 10, 2000);

        HANDLE hth1 = NULL;

        unsigned uiThread1ID;

        hth1 =(HANDLE) _beginthreadex(NULL,

            0,

            ThreadX::ThreadStaticEntryPoint,

            pThX,

            CREATE_SUSPENDED,

            &uiThread1ID);

        if (hth1 == NULL){

            cout << "failed to create thread 1" << endl;

           

        }

        DWORD dwExitCode;

        GetExitCodeThread(hth1, &dwExitCode); // shoule be STILL_ACTIVE

        cout << "init thread 1 exit code id = " << dwExitCode << endl;

        pThX->threadName = "yang1";

     

        ThreadX* pThX2 = new ThreadX(0, 10, 2000);

        HANDLE hth2 = NULL;

        unsigned uiThread2ID;

        hth2 = (HANDLE) _beginthreadex(NULL,

            0,

            ThreadX::ThreadStaticEntryPoint,

            pThX2,

            CREATE_SUSPENDED,

            &uiThread2ID);

        if (hth2 == NULL){

            cout << "create thread 2 failed" << endl;

           

        }

        GetExitCodeThread(hth2, &dwExitCode);

        cout << "init thread 2 exit code id = " << dwExitCode << endl;

        pThX2->threadName = "yang2";

     

        ResumeThread(hth1);

        ResumeThread(hth2);

     

        WaitForSingleObject(hth1, INFINITE);

        WaitForSingleObject(hth2, INFINITE);

     

        GetExitCodeThread(hth1, &dwExitCode);

        cout << "thread 1 exited with exit code " << dwExitCode << endl;

        GetExitCodeThread(hth2, &dwExitCode);

        cout << "thread 2 exited with exit code " << dwExitCode << endl;

     

        CloseHandle(hth1);

        CloseHandle(hth2);

     

        delete pThX;

        delete pThX2;

        pThX = NULL;

        pThX2 = NULL;

        cout << "end program  " << endl;

     

        return 0;

    }

    2.线程临界区

             线程之间共享的对象,当修改的时候,只能够一个线程修改,同时不存在其他的线程访问该资源,这就是线程之间的同步问题.在上一篇总结中使用的是CreateMutex函数创建一个HANDLE,这样的话创建一个Mutex,当线程访问资源的时候,使用WaitForSimpleObject(handl,  INFINITE);获得该对象的锁,然后再使用完的时候,释放对象锁,ReleaseMutex(handle);

             在线程中有一个概念是临界区,在C++中使用这一种实现的,就是用CRITICAL_SECTION 声明一个临界区变量,然后再程序开始的时候,使用InitializeCriticalSelection(CRITICAL_SELECTION*) 初始化临界变量,然后当线程进入临界区的时候,使用EneterCriticalSelection(CRITICAL_SELECTION*);当访问完成的时候使用LeaveCriticalSelection(CRITICAL_SELECTION);

    #include <iostream>

    #include<Windows.h>

    using namespace std;

    bool g_bContinue = true;

    int g_count1 = 0;

    int g_count2 = 0;

     

    DWORD WINAPI ThreadProc(LPVOID lpParam){

        for (int i = 0; i < 20; i++)

        {

            EnterCriticalSection(&g_cs);

            g_count1++;

            g_count2++;

            LeaveCriticalSection(&g_cs);

        }

        return 0;

    }

     

    int main(){

        HANDLE g_hThr[2];

        InitializeCriticalSection(&g_cs);

        g_hThr[0] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

        g_hThr[1] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

     

        WaitForSingleObject( g_hThr[0], INFINITE);

        WaitForSingleObject( g_hThr[1], INFINITE);

        g_bContinue = false;

        CloseHandle(g_hThr[0]);

        CloseHandle(g_hThr[1]);

        DeleteCriticalSection(&g_cs);

     

        Sleep(1000);

        cout << "g_count1 = " << g_count1 << " g_count2 = " << g_count2 << endl;

    }

    追梦的飞飞

    于广州中山大学 20131022

    HomePage: http://yangtengfei.duapp.com

  • 相关阅读:
    Spring_IOC理论推导
    第一个Mybatis及运行问题分析
    Spring_简介
    ECharts_雷达图
    ECharts_饼图
    ECharts_直角坐标系的常用配置
    ECharts_散点图
    ECharts_折线图
    util之日期工具类
    util之Json工具类
  • 原文地址:https://www.cnblogs.com/hbhzsysutengfei/p/3409483.html
Copyright © 2011-2022 走看看