zoukankan      html  css  js  c++  java
  • C/C++ Runtime 多线程函数

    一 简单实例(来自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
    主线程创建2个线程t1和t2,创建时2个线程就被挂起,后来调用ResumeThread恢复2个线程,是其开始执行,调用WaitForSingleObject等待2个线程执行完,然后推出主线程即结束进程。

    /*  file Main.cpp
     *
     *  This program is an adaptation of the code Rex Jaeschke showed in
     *  Listing 1 of his Oct 2005 C/C++ User's Journal article entitled
     *  "C++/CLI Threading: Part I".  I changed it from C++/CLI (managed)
     *  code to standard C++.
     *
     *  One hassle is the fact that C++ must employ a free (C) function
     *  or a static class member function as the thread entry function.
     *
     *  This program must be compiled with a multi-threaded C run-time
     *  (/MT for LIBCMT.LIB in a release build or /MTd for LIBCMTD.LIB
     *  in a debug build).
     *
     *                                      John Kopplin  7/2006
     
    */



    #include 
    <stdio.h>
    #include 
    <string>             // for STL string class
    #include <windows.h>          // for HANDLE
    #include <process.h>          // for _beginthread()

    using namespace std;


    class ThreadX
    {
    private:
      
    int loopStart;
      
    int loopEnd;
      
    int dispFrequency;

    public:
      
    string threadName;

      ThreadX( 
    int startValue, int endValue, int frequency )
      
    {
        loopStart 
    = startValue;
        loopEnd 
    = endValue;
        dispFrequency 
    = frequency;
      }


      
    // In C++ you must employ a free (C) function or a static
      
    // class member function as the thread entry-point-function.
      
    // Furthermore, _beginthreadex() demands that the thread
      
    // entry function signature take a single (void*) and returned
      
    // an unsigned.
      static unsigned __stdcall ThreadStaticEntryPoint(void * pThis)
      
    {
          ThreadX 
    * pthX = (ThreadX*)pThis;   // the tricky cast
          pthX->ThreadEntryPoint();           // now call the true entry-point-function

          
    // A thread terminates automatically if it completes execution,
          
    // or it can terminate itself with a call to _endthread().

          
    return 1;          // the thread exit code
      }


      
    void ThreadEntryPoint()
      
    {
         
    // This is the desired entry-point-function but to get
         
    // here we have to use a 2 step procedure involving
         
    // the ThreadStaticEntryPoint() function.

        
    for (int i = loopStart; i <= loopEnd; ++i)
        
    {
          
    if (i % dispFrequency == 0)
          
    {
              printf( 
    "%s: i = %d\n", threadName.c_str(), i );
          }

        }

        printf( 
    "%s thread terminating\n", threadName.c_str() );
      }

    }
    ;


    int main()
    {
        
    // All processes get a primary thread automatically. This primary
        
    // thread can generate additional threads.  In this program the
        
    // primary thread creates 2 additional threads and all 3 threads
        
    // then run simultaneously without any synchronization.  No data
        
    // is shared between the threads.

        
    // We instantiate an object of the ThreadX class. Next we will
        
    // create a thread and specify that the thread is to begin executing
        
    // the function ThreadEntryPoint() on object o1. Once started,
        
    // this thread will execute until that function terminates or
        
    // until the overall process terminates.

        ThreadX 
    * o1 = new ThreadX( 012000 );

        
    // When developing a multithreaded WIN32-based application with
        
    // Visual C++, you need to use the CRT thread functions to create
        
    // any threads that call CRT functions. Hence to create and terminate
        
    // threads, use _beginthreadex() and _endthreadex() instead of
        
    // the Win32 APIs CreateThread() and EndThread().

        
    // The multithread library LIBCMT.LIB includes the _beginthread()
        
    // and _endthread() functions. The _beginthread() function performs
        
    // initialization without which many C run-time functions will fail.
        
    // You must use _beginthread() instead of CreateThread() in C programs
        
    // built with LIBCMT.LIB if you intend to call C run-time functions.

        
    // Unlike the thread handle returned by _beginthread(), the thread handle
        
    // returned by _beginthreadex() can be used with the synchronization APIs.

        HANDLE   hth1;
        unsigned  uiThread1ID;

        hth1 
    = (HANDLE)_beginthreadex( NULL,         // security
                                       0,            // stack size
                                       ThreadX::ThreadStaticEntryPoint,
                                       o1,           
    // arg list
                                       CREATE_SUSPENDED,  // so we can later call ResumeThread()
                                       &uiThread1ID );

        
    if ( hth1 == 0 )
            printf(
    "Failed to create thread 1\n");

        DWORD   dwExitCode;

        GetExitCodeThread( hth1, 
    &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
        printf( "initial thread 1 exit code = %u\n", dwExitCode );

        
    // The System::Threading::Thread object in C++/CLI has a "Name" property.
        
    // To create the equivalent functionality in C++ I added a public data member
        
    // named threadName.

        o1
    ->threadName = "t1";

        ThreadX 
    * o2 = new ThreadX( -100000002000 );

        HANDLE   hth2;
        unsigned  uiThread2ID;

        hth2 
    = (HANDLE)_beginthreadex( NULL,         // security
                                       0,            // stack size
                                       ThreadX::ThreadStaticEntryPoint,
                                       o2,           
    // arg list
                                       CREATE_SUSPENDED,  // so we can later call ResumeThread()
                                       &uiThread2ID );

        
    if ( hth2 == 0 )
            printf(
    "Failed to create thread 2\n");

        GetExitCodeThread( hth2, 
    &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
        printf( "initial thread 2 exit code = %u\n", dwExitCode );

        o2
    ->threadName = "t2";

        
    // If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()
        
    // we wouldn't now need to call ResumeThread().

        ResumeThread( hth1 );   
    // serves the purpose of Jaeschke's t1->Start()

        ResumeThread( hth2 );

        
    // In C++/CLI the process continues until the last thread exits.
        
    // That is, the thread's have independent lifetimes. Hence
        
    // Jaeschke's original code was designed to show that the primary
        
    // thread could exit and not influence the other threads.

        
    // However in C++ the process terminates when the primary thread exits
        
    // and when the process terminates all its threads are then terminated.
        
    // Hence if you comment out the following waits, the non-primary
        
    // threads will never get a chance to run.

        WaitForSingleObject( hth1, INFINITE );
        WaitForSingleObject( hth2, INFINITE );

        GetExitCodeThread( hth1, 
    &dwExitCode );
        printf( 
    "thread 1 exited with code %u\n", dwExitCode );

        GetExitCodeThread( hth2, 
    &dwExitCode );
        printf( 
    "thread 2 exited with code %u\n", dwExitCode );

        
    // The handle returned by _beginthreadex() has to be closed
        
    // by the caller of _beginthreadex().

        CloseHandle( hth1 );
        CloseHandle( hth2 );

        delete o1;
        o1 
    = NULL;

        delete o2;
        o2 
    = NULL;

        printf(
    "Primary thread terminating.\n");
    }


    二解释
    1)如果你正在编写C/C++代码,决不应该调用CreateThread。相反,应该使用VisualC++运行期库函数_beginthreadex,推出也应该使用_endthreadex。如果不使用Microsoft的VisualC++编译器,你的编译器供应商有它自己的CreateThred替代函数。不管这个替代函数是什么,你都必须使用。

    2)因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MT或MTD。

    3) _beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的,但是参数名和类型并不完全相同。这是因为Microsoft的C/C++运行期库的开发小组认为,C/C++运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样,返回新创建的线程的句柄。
    下面是关于_beginthreadex的一些要点:
    •每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件中的VisualC++源代码中)。

    •传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。

    •_beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。

    •当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。

    •如果一切顺利,就会像CreateThread那样返回线程句柄。如果任何操作失败了,便返回NULL。

    4) _endthreadex的一些要点:
    •C运行期库的_getptd函数内部调用操作系统的TlsGetValue函数,该函数负责检索调用线程的tiddata内存块的地址。

    •然后该数据块被释放,而操作系统的ExitThread函数被调用,以便真正撤消该线程。当然,退出代码要正确地设置和传递。

    5)虽然也提供了简化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

    6)线程handle因为是内核对象,所以需要在最后closehandle。

    7)更多的API:HANDLE GetCurrentProcess();HANDLE GetCurrentThread();DWORD GetCurrentProcessId();DWORD GetCurrentThreadId()。DWORD SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor);BOOL SetThreadPriority(HANDLE hThread,int nPriority);BOOL SetPriorityClass(GetCurrentProcess(),  IDLE_PRIORITY_CLASS);BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);BOOL SwitchToThread();

    三注意
    1)C++主线程的终止,同时也会终止所有主线程创建的子线程,不管子线程有没有执行完毕。所以上面的代码中如果不调用WaitForSingleObject,则2个子线程t1和t2可能并没有执行完毕或根本没有执行。
    2)如果某线程挂起,然后有调用WaitForSingleObject等待该线程,就会导致死锁。所以上面的代码如果不调用resumethread,则会死锁。

  • 相关阅读:
    服务器状态码
    QuerySet中添加Extra进行SQL查询
    django配置一个网站建设
    MySQL数据库查询中的特殊命令
    125. Valid Palindrome
    121. Best Time to Buy and Sell Stock
    117. Populating Next Right Pointers in Each Node II
    98. Validate Binary Search Tree
    91. Decode Ways
    90. Subsets II
  • 原文地址:https://www.cnblogs.com/cy163/p/1560158.html
Copyright © 2011-2022 走看看