pthread-win32库编译及使用方法注意事项

来源:互联网 发布:linux中cd的使用 编辑:程序博客网 时间:2024/05/16 15:42
开篇提示:本文欢迎转载,但必须注明本文出处,例如:
“该文引用自 CruiseYoung的:pthread-win32库编译及使用方法注意事项   http://blog.csdn.net/fksec/article/details/41517953”   
否则说明阁下愿意支付以100元人民币每字计的稿费,敬请留意。

1 官网

1.1 POSIX Threads (pthreads) for Win32
http://www.sourceware.org/pthreads-win32/
下载地址:ftp://sourceware.org/pub/pthreads-win32/
1.2 当前最新版本为:PTHREADS-WIN32 RELEASE 2.9.1 (2012-05-27)
下载到的文件为pthreads-w32-2-9-1-release.zip
解压到“pthreads-w32-2-9-1-release”目录,里面有三个子目录:
pre-build.2 pthreads.2 QueueUserAPCEx
Pthreads.2 里面包含了pthreads 的源代码;
Pre-build.2 里面包含了include和 lib 分别包含了pthreads for win32 的头文件和库文件(包括动态连接库)。以下做法不推荐:将include 和lib 里面的内容分别复制到你的编译器的include 和 lib 目录,同时将lib 目录中的 dll 文件copy 到操作系统的system32 文件夹中或应用程序执行目录。
QueueUserAPCEx 里面是一个alert的driver,编译需要DDK ,默认vs2013 没有安装。Windows Device Driver Kit (NTDDK.h) 需要额外单独安装。

2 源代码编译

虽然源码包里提供了vc6的项目文件, 但是我不推荐直接打开, 而推荐用nmake.默认的会告诉你一堆nmake参数的. 
:请仔细阅读:
pthreads-w32-2-9-1-release\pthreads.2\README(系列文件)pthreads-w32-2-9-1-release\pthreads.2\tests\README
2.1 命令选取:
参考文档:pthreads-w32-2-9-1-release\pthreads.2\Nmakefile
编译库我选取以下4个命令:
nmake clean VC-static (to build the MSVC static lib with C cleanup code)nmake clean VC-static-debug (to build the debug MSVC static lib with C cleanup code)nmake clean VC-inlined (to build the MSVC inlined dll with C cleanup code)nmake clean VC-inlined-debug (to build the debug MSVC inlined dll with C cleanup code)
参考文档:pthreads-w32-2-9-1-release\pthreads.2\tests\Makefile
测试我选取以下2个命令
nmake clean VC (to test using VC dll with VC (no EH) applications)nmake clean VC-static (to test using VC static lib with VC (no EH) applications)
2.2 Nmakefile文件修改
将pthreads-w32-2-9-1-release\pthreads.2\Nmakefile文件中的以下语句
install:copy pthread*.dll $(DLLDEST)copy pthread*.lib $(LIBDEST)copy pthread.h $(HDRDEST)copy sched.h $(HDRDEST)copy semaphore.h $(HDRDEST)
替换为:
install:if not exist $(DEVROOT) mkdir $(DEVROOT)if not exist $(DLLDEST) mkdir $(DLLDEST)if not exist $(LIBDEST) mkdir $(LIBDEST)if not exist $(HDRDEST) mkdir $(HDRDEST)xcopy /H /Y /R /I /V /K pthread*.dll $(DLLDEST)xcopy /H /Y /R /I /V /K pthread*.pdb $(LIBDEST)copy /Y pthread*.lib $(LIBDEST)copy /Y pthread.h $(HDRDEST)copy /Y sched.h $(HDRDEST)copy /Y semaphore.h $(HDRDEST)
2.3 编译命令
通过对“pthreads-w32-2-9-1-release\pthreads.2\Nmakefile”分析,本人对编译命令我稍作修改。
x64编译:
nmake realclean VC-inlined-debugnmake DEVROOT=D:\comm\pthreads\debug_x64 installnmake realclean VC-inlinednmake DEVROOT=D:\comm\pthreads\release_x64 installcd testsnmake clean VCnmake cleancd ..nmake realclean VC-static-debugnmake DEVROOT=D:\comm\pthreads\debug_x64_static installnmake realclean VC-staticnmake DEVROOT=D:\comm\pthreads\release_x64_static installcd testsnmake clean VC-staticnmake cleancd ..
x86编译:
nmake realclean VC-inlined-debugnmake DEVROOT=D:\comm\pthreads\debug_x86 installnmake realclean VC-inlinednmake DEVROOT=D:\comm\pthreads\release_x86 installcd testsnmake clean VCnmake cleancd ..nmake realclean VC-static-debugnmake DEVROOT=D:\comm\pthreads\debug_x86_static installnmake realclean VC-staticnmake DEVROOT=D:\comm\pthreads\release_x86_static installcd testsnmake clean VC-staticnmake cleancd ..
两步合一(只编译库):
x64编译:
nmake realclean VC-inlined-debug DEVROOT=D:\comm\pthreads\debug_x64 installnmake realclean VC-inlined DEVROOT=D:\comm\pthreads\release_x64 installnmake realclean VC-static-debug DEVROOT=D:\comm\pthreads\debug_x64_static installnmake realclean VC-static DEVROOT=D:\comm\pthreads\release_x64_static install
x86编译:
nmake realclean VC-inlined-debug DEVROOT=D:\comm\pthreads\debug_x86 installnmake realclean VC-inlined DEVROOT=D:\\comm\pthreads\release_x86 installnmake realclean VC-static-debug DEVROOT=D:\comm\pthreads\debug_x86_static installnmake realclean VC-static DEVROOT=D:\comm\pthreads\release_x86_static install

3 pthread-win32应用注意事项

注:在此请仔细阅读pthreads-w32-2-9-1-release\pthreads.2\README文件
3.1 pthreadVCE或pthreadGCE使用注意事项
原文摘录
[If you use either pthreadVCE or pthreadGCE]1. [See also the discussion in the FAQ file - Q2, Q4, and Q5]If your application contains catch(...) blocks in your POSIXthreads then you will need to replace the "catch(...)" with the macro"PtW32Catch", eg.#ifdef PtW32CatchPtW32Catch {...}#elsecatch(...) {...}#endifOtherwise neither pthreads cancelation nor pthread_exit() will workreliably when using versions of the library that use C++ exceptionsfor cancelation and thread exit.This is due to what is believed to be a C++ compliance error in VC++whereby you may not have multiple handlers for the same exception inthe same try/catch block. GNU G++ doesn't have this restriction.
3.2 Cleanup代码默认形式
原文摘录
Cleanup code default style--------------------------Previously, if not defined, the cleanup style was determined automaticallyfrom the compiler used, and one of the following was defined accordingly:__CLEANUP_SEHMSVC only__CLEANUP_CXXC++, including MSVC++, GNU G++__CLEANUP_CC, including GNU GCC, not MSVCThese defines determine the style of cleanup (see pthread.h) and,most importantly, the way that cancelation and thread exit (viapthread_exit) is performed (see the routine ptw32_throw()).In short, the exceptions versions of the library throw an exceptionwhen a thread is canceled, or exits via pthread_exit(). This exception iscaught by a handler in the thread startup routine, so that thethe correct stack unwinding occurs regardless of where the threadis when it's canceled or exits via pthread_exit().In this snapshot, unless the build explicitly defines (e.g. via acompiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, thenthe build NOW always defaults to __CLEANUP_C style cleanup. This styleuses setjmp/longjmp in the cancelation and pthread_exit implementations,and therefore won't do stack unwinding even when linked to applicationsthat have it (e.g. C++ apps). This is for consistency with most/allcommercial Unix POSIX threads implementations.Although it was not clearly documented before, it is still necessary tobuild your application using the same __CLEANUP_* define as wasused for the version of the library that you link with, so that thecorrect parts of pthread.h are included. That is, the possibledefines require the following library versions:__CLEANUP_SEHpthreadVSE.dll__CLEANUP_CXXpthreadVCE.dll or pthreadGCE.dll__CLEANUP_CpthreadVC.dll or pthreadGC.dllIt is recommended that you let pthread.h use it's default __CLEANUP_Cfor both library and application builds. That is, don't define any ofthe above, and then link with pthreadVC.lib (MSVC or MSVC++) andlibpthreadGC.a (MinGW GCC or G++). The reason is explained below, butanother reason is that the prebuilt pthreadVCE.dll is currently broken.Versions built with MSVC++ later than version 6 may not be broken, but Ican't verify this yet.WHY ARE WE MAKING THE DEFAULT STYLE LESS EXCEPTION-FRIENDLY?Because no commercial Unix POSIX threads implementation allows you tochoose to have stack unwinding. Therefore, providing it in pthread-win32as a default is dangerous. We still provide the choice but unlessyou consciously choose to do otherwise, your pthreads applications willnow run or crash in similar ways irrespective of the pthreads platformyou use. Or at least this is the hope.
3.3 静态库编译及使用(重中之重)
原文摘录
Building the library as a statically linkable library-----------------------------------------------------General: PTW32_STATIC_LIB must be defined for both the library build and theapplication build. The makefiles supplied and used by the following 'make'command lines will define this for you.MSVC (creates pthreadVCn.lib as a static link lib):nmake clean VC-staticMinGW32 (creates libpthreadGCn.a as a static link lib):make clean GC-staticDefine PTW32_STATIC_LIB when building your application. Also, yourapplication must call a two non-portable routines to initialise thesome state on startup and cleanup before exit. One other routine needsto be called to cleanup after any Win32 threads have called POSIX APIroutines. See README.NONPORTABLE or the html reference manual pages fordetails on these routines:BOOL pthread_win32_process_attach_np (void);BOOL pthread_win32_process_detach_np (void);BOOL pthread_win32_thread_attach_np (void); // Currently a no-opBOOL pthread_win32_thread_detach_np (void);The tests makefiles have the same targets but only check that thestatic library is statically linkable. They don't run the fulltestsuite. To run the full testsuite, build the dlls and run thedll test targets.
3.4 pthread_win32不可移植的特性及问题(非常重要)
详见pthreads-w32-2-9-1-release\pthreads.2\README.NONPORTABLE文件
原文摘录
This file documents non-portable functions and other issues.Non-portable functions included in pthreads-win32-------------------------------------------------BOOLpthread_win32_test_features_np(int mask)This routine allows an application to check whichrun-time auto-detected features are available withinthe library.The possible features are:PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGEReturn TRUE if the native version ofInterlockedCompareExchange() is being used.This feature is not meaningful in recentlibrary versions as MSVC builds only supportsystem implemented ICE. Note that all Mingwbuilds use inlined asm versions of all theInterlocked routines.PTW32_ALERTABLE_ASYNC_CANCELReturn TRUE is the QueueUserAPCEx packageQUSEREX.DLL is available and the AlertDrv.sysdriver is loaded into Windows, providingalertable (pre-emptive) asyncronous threadscancelation. If this feature returns FALSEthen the default async cancel scheme is inuse, which cannot cancel blocked threads.Features may be Or'ed into the mask parameter, in which casethe routine returns TRUE if any of the Or'ed features wouldreturn TRUE. At this stage it doesn't make sense to Or featuresbut it may some day.void *pthread_timechange_handler_np(void *)        To improve tolerance against operator or time service        initiated system clock changes.        This routine can be called by an application when it        receives a WM_TIMECHANGE message from the system. At        present it broadcasts all condition variables so that        waiting threads can wake up and re-evaluate their        conditions and restart their timed waits if required.        It has the same return type and argument type as a        thread routine so that it may be called directly        through pthread_create(), i.e. as a separate thread.        Parameters        Although a parameter must be supplied, it is ignored.        The value NULL can be used.        Return values        It can return an error EAGAIN to indicate that not        all condition variables were broadcast for some reason.        Otherwise, 0 is returned.        If run as a thread, the return value is returned        through pthread_join().        The return value should be cast to an integer.HANDLEpthread_getw32threadhandle_np(pthread_t thread);Returns the win32 thread handle that the POSIXthread "thread" is running as.Applications can use the win32 handle to setwin32 specific attributes of the thread.DWORDpthread_getw32threadid_np (pthread_t thread)Returns the Windows native thread ID that the POSIXthread "thread" is running as.        Only valid when the library is built where        ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__)        and otherwise returns 0.intpthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind)intpthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind)        These two routines are included for Linux compatibility        and are direct equivalents to the standard routines                pthread_mutexattr_settype                pthread_mutexattr_gettype        pthread_mutexattr_setkind_np accepts the following        mutex kinds:                PTHREAD_MUTEX_FAST_NP                PTHREAD_MUTEX_ERRORCHECK_NP                PTHREAD_MUTEX_RECURSIVE_NP        These are really just equivalent to (respectively):                PTHREAD_MUTEX_NORMAL                PTHREAD_MUTEX_ERRORCHECK                PTHREAD_MUTEX_RECURSIVEintpthread_delay_np (const struct timespec *interval);        This routine causes a thread to delay execution for a specific period of time.        This period ends at the current time plus the specified interval. The routine        will not return before the end of the period is reached, but may return an        arbitrary amount of time after the period has gone by. This can be due to        system load, thread priorities, and system timer granularity.        Specifying an interval of zero (0) seconds and zero (0) nanoseconds is        allowed and can be used to force the thread to give up the processor or to        deliver a pending cancelation request.        This routine is a cancelation point.        The timespec structure contains the following two fields:                tv_sec is an integer number of seconds.                tv_nsec is an integer number of nanoseconds.         Return Values        If an error condition occurs, this routine returns an integer value        indicating the type of error. Possible return values are as follows:        0          Successful completion.         [EINVAL]   The value specified by interval is invalid. intpthread_num_processors_np (void)        This routine (found on HPUX systems) returns the number of processors        in the system. This implementation actually returns the number of        processors available to the process, which can be a lower number        than the system's number, depending on the process's affinity mask.BOOLpthread_win32_process_attach_np (void);BOOLpthread_win32_process_detach_np (void);BOOLpthread_win32_thread_attach_np (void);BOOLpthread_win32_thread_detach_np (void);These functions contain the code normally run via dllMainwhen the library is used as a dll but which need to becalled explicitly by an application when the libraryis statically linked. As of version 2.9.0 of the library, staticbuilds using either MSC or GCC will call pthread_win32_process_*automatically at application startup and exit respectively.Otherwise, you will need to call pthread_win32_process_attach_np()before you can call any pthread routines when statically linking.You should call pthread_win32_process_detach_np() beforeexiting your application to clean up.pthread_win32_thread_attach_np() is currently a no-op, butpthread_win32_thread_detach_np() is needed to clean upthe implicit pthread handle that is allocated to a Win32 thread ifit calls any pthreads routines. Call this routine when theWin32 thread exits.Threads created through pthread_create() do notneed to callpthread_win32_thread_detach_np().These functions invariably return TRUE except forpthread_win32_process_attach_np() which will return FALSEif pthreads-win32 initialisation fails.intpthreadCancelableWait (HANDLE waitHandle);intpthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);These two functions provide hooks into the pthread_cancelmechanism that will allow you to wait on a Windows handleand make it a cancellation point. Both functions blockuntil either the given w32 handle is signaled, orpthread_cancel has been called. It is implemented usingWaitForMultipleObjects on 'waitHandle' and a manuallyreset w32 event used to implement pthread_cancel.Non-portable issues-------------------Thread priorityPOSIX defines a single contiguous range of numbers that determine athread's priority. Win32 defines priority classes and prioritylevels relative to these classes. Classes are simply priority baselevels that the defined priority levels are relative to such that,changing a process's priority class will change the priority of allof it's threads, while the threads retain the same relativity to eachother.A Win32 system defines a single contiguous monotonic range of valuesthat define system priority levels, just like POSIX. However, Win32restricts individual threads to a subset of this range on aper-process basis.The following table shows the base priority levels for combinationsof priority class and priority value in Win32. Process Priority Class               Thread Priority Level ----------------------------------------------------------------- 1 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_IDLE 1 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_IDLE 1 NORMAL_PRIORITY_CLASS              THREAD_PRIORITY_IDLE 1 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_IDLE 1 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_IDLE 2 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_LOWEST 3 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_BELOW_NORMAL 4 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_NORMAL 4 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_LOWEST 5 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_ABOVE_NORMAL 5 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_BELOW_NORMAL 5 Background NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_LOWEST 6 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_HIGHEST 6 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_NORMAL 6 Background NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_BELOW_NORMAL 7 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_ABOVE_NORMAL 7 Background NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_NORMAL 7 Foreground NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_LOWEST  8 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_HIGHEST 8 NORMAL_PRIORITY_CLASS              THREAD_PRIORITY_ABOVE_NORMAL 8 Foreground NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_BELOW_NORMAL 8 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_LOWEST 9 NORMAL_PRIORITY_CLASS              THREAD_PRIORITY_HIGHEST 9 Foreground NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_NORMAL 9 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_BELOW_NORMAL10 Foreground NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_ABOVE_NORMAL10 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_NORMAL11 Foreground NORMAL_PRIORITY_CLASS   THREAD_PRIORITY_HIGHEST11 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_ABOVE_NORMAL11 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_LOWEST12 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_HIGHEST12 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_BELOW_NORMAL13 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_NORMAL14 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_ABOVE_NORMAL15 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_HIGHEST15 HIGH_PRIORITY_CLASS                THREAD_PRIORITY_TIME_CRITICAL15 IDLE_PRIORITY_CLASS                THREAD_PRIORITY_TIME_CRITICAL15 BELOW_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_TIME_CRITICAL15 NORMAL_PRIORITY_CLASS              THREAD_PRIORITY_TIME_CRITICAL15 ABOVE_NORMAL_PRIORITY_CLASS        THREAD_PRIORITY_TIME_CRITICAL16 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_IDLE17 REALTIME_PRIORITY_CLASS            -718 REALTIME_PRIORITY_CLASS            -619 REALTIME_PRIORITY_CLASS            -520 REALTIME_PRIORITY_CLASS            -421 REALTIME_PRIORITY_CLASS            -322 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_LOWEST23 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_BELOW_NORMAL24 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_NORMAL25 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_ABOVE_NORMAL26 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_HIGHEST27 REALTIME_PRIORITY_CLASS             328 REALTIME_PRIORITY_CLASS             429 REALTIME_PRIORITY_CLASS             530 REALTIME_PRIORITY_CLASS             631 REALTIME_PRIORITY_CLASS            THREAD_PRIORITY_TIME_CRITICALWindows NT:  Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported.As you can see, the real priority levels available to any individualWin32 thread are non-contiguous.An application using pthreads-win32 should not make assumptions aboutthe numbers used to represent thread priority levels, except that theyare monotonic between the values returned by sched_get_priority_min()and sched_get_priority_max(). E.g. Windows 95, 98, NT, 2000, XP makeavailable a non-contiguous range of numbers between -15 and 15, whileat least one version of WinCE (3.0) defines the minimum priority(THREAD_PRIORITY_LOWEST) as 5, and the maximum priority(THREAD_PRIORITY_HIGHEST) as 1.Internally, pthreads-win32 maps any priority levels betweenTHREAD_PRIORITY_IDLE and THREAD_PRIORITY_LOWEST to THREAD_PRIORITY_LOWEST,or between THREAD_PRIORITY_TIME_CRITICAL and THREAD_PRIORITY_HIGHEST toTHREAD_PRIORITY_HIGHEST. Currently, this also applies toREALTIME_PRIORITY_CLASSi even if levels -7, -6, -5, -4, -3, 3, 4, 5, and 6are supported.If it wishes, a Win32 application using pthreads-win32 can use the Win32defined priority macros THREAD_PRIORITY_IDLE throughTHREAD_PRIORITY_TIME_CRITICAL.The opacity of the pthread_t datatype-------------------------------------and possible solutions for portable null/compare/hash, etc----------------------------------------------------------Because pthread_t is an opague datatype an implementation is permitted to definepthread_t in any way it wishes. That includes defining some bits, if it isscalar, or members, if it is an aggregate, to store information that may beextra to the unique identifying value of the ID. As a result, pthread_t valuesmay not be directly comparable.If you want your code to be portable you must adhere to the following contraints:1) Don't assume it is a scalar data type, e.g. an integer or pointer value. Thereare several other implementations where pthread_t is also a struct. See our FAQQuestion 11 for our reasons for defining pthread_t as a struct.2) You must not compare them using relational or equality operators. You must usethe API function pthread_equal() to test for equality.3) Never attempt to reference individual members.The problemCertain applications would like to be able to access only the 'pure' pthread_tid values, primarily to use as keys into data structures to manage threads orthread-related data, but this is not possible in a maximally portable andstandards compliant way for current POSIX threads implementations.For implementations that define pthread_t as a scalar, programmers often employdirect relational and equality operators on pthread_t. This code will break whenported to an implementation that defines pthread_t as an aggregate type.For implementations that define pthread_t as an aggregate, e.g. a struct,programmers can use memcmp etc., but then face the prospect that the struct mayinclude alignment padding bytes or bits as well as extra implementation-specificmembers that are not part of the unique identifying value.[While this is not currently the case for pthreads-win32, opacity alsomeans that an implementation is free to change the definition, which shouldgenerally only require that applications be recompiled and relinked, notrewritten.]Doesn't the compiler take care of padding?The C89 and later standards only effectively guarrantee element-by-elementequivalence following an assignment or pass by value of a struct or union,therefore undefined areas of any two otherwise equivalent pthread_t instancescan still compare differently, e.g. attempting to compare two such pthread_tvariables byte-by-byte, e.g. memcmp(&t1, &t2, sizeof(pthread_t) may give anincorrect result. In practice I'm reasonably confident that compilers routinelyalso copy the padding bytes, mainly because assignment of unions would be fartoo complicated otherwise. But it just isn't guarranteed by the standard.Illustration:We have two thread IDs t1 and t2pthread_t t1, t2;In an application we create the threads and intend to store the thread IDs in anordered data structure (linked list, tree, etc) so we need to be able to comparethem in order to insert them initially and also to traverse.Suppose pthread_t contains undefined padding bits and our compiler copies ourpthread_t [struct] element-by-element, then for the assignment:pthread_t temp = t1;temp and t1 will be equivalent and correct but a byte-for-byte comparison such asmemcmp(&temp, &t1, sizeof(pthread_t)) == 0 may not return true as we expect becausethe undefined bits may not have the same values in the two variable instances.Similarly if passing by value under the same conditions.If, on the other hand, the undefined bits are at least constant through everyassignment and pass-by-value then the byte-for-byte comparisonmemcmp(&temp, &t1, sizeof(pthread_t)) == 0 will always return the expected result.How can we force the behaviour we need?SolutionsAdding new functions to the standard API or as non-portable extentions isthe only reliable and portable way to provide the necessary operations.Remember also that POSIX is not tied to the C language. The most commonfunctions that have been suggested are:pthread_null()pthread_compare()pthread_hash()A single more general purpose function could also be defined as abasis for at least the last two of the above functions.First we need to list the freedoms and constraints with restpectto pthread_t so that we can be sure our solution is compatible with thestandard.What is known or may be deduced from the standard:1) pthread_t must be able to be passed by value, so it must be a single object.2) from (1) it must be copyable so cannot embed thread-state information, locksor other volatile objects required to manage the thread it associates with.3) pthread_t may carry additional information, e.g. for debugging or to manageitself.4) there is an implicit requirement that the size of pthread_t is determinableat compile-time and size-invariant, because it must be able to copy the object(i.e. through assignment and pass-by-value). Such copies must be genuineduplicates, not merely a copy of a pointer to a common instance such aswould be the case if pthread_t were defined as an array.Suppose we define the following function:/* This function shall return it's argument */pthread_t* pthread_normalize(pthread_t* thread);For scalar or aggregate pthread_t types this function would simply zero any bitswithin the pthread_t that don't uniquely identify the thread, including padding,such that client code can return consistent results from operations done on theresult. If the additional bits are a pointer to an associate structure thenthis function would ensure that the memory used to store that associatestructure does not leak. After normalization the following compare would bevalid and repeatable:memcmp(pthread_normalize(&t1),pthread_normalize(&t2),sizeof(pthread_t))Note 1: such comparisons are intended merely to order and sort pthread_t valuesand allow them to index various data structures. They are not intended to revealanything about the relationships between threads, like startup order.Note 2: the normalized pthread_t is also a valid pthread_t that uniquelyidentifies the same thread.Advantages:1) In most existing implementations this function would reduce to a no-op thatemits no additional instructions, i.e after in-lining or optimisation, or ifdefined as a macro:#define pthread_normalise(tptr) (tptr)2) This single function allows an application to portably deriveapplication-level versions of any of the other required functions.3) It is a generic function that could enable unanticipated uses.Disadvantages:1) Less efficient than dedicated compare or hash functions for implementationsthat include significant extra non-id elements in pthread_t.2) Still need to be concerned about padding if copying normalized pthread_t.See the later section on defining pthread_t to neutralise padding issues.Generally a pthread_t may need to be normalized every time it is used,which could have a significant impact. However, this is a design decisionfor the implementor in a competitive environment. An implementation is freeto define a pthread_t in a way that minimises or eliminates padding orrenders this function a no-op.Hazards:1) Pass-by-reference directly modifies 'thread' so the application mustsynchronise access or ensure that the pointer refers to a copy. The alternativeof pass-by-value/return-by-value was considered but then this requires two copyoperations, disadvantaging implementations where this function is not a no-opin terms of speed of execution. This function is intended to be used in highfrequency situations and needs to be efficient, or at least not unnecessarilyinefficient. The alternative also sits awkwardly with functions like memcmp.2) [Non-compliant] code that uses relational and equality operators onarithmetic or pointer style pthread_t types would need to be rewritten, but itshould be rewritten anyway.C implementation of null/compare/hash functions using pthread_normalize():/* In pthread.h */pthread_t* pthread_normalize(pthread_t* thread);/* In user code *//* User-level bitclear function - clear bits in loc corresponding to mask */void* bitclear (void* loc, void* mask, size_t count);typedef unsigned int hash_t;/* User-level hash function */hash_t hash(void* ptr, size_t count);/* * User-level pthr_null function - modifies the origin thread handle. * The concept of a null pthread_t is highly implementation dependent * and this design may be far from the mark. For example, in an * implementation "null" may mean setting a special value inside one * element of pthread_t to mean "INVALID". However, if that value was zero and * formed part of the id component then we may get away with this design. */pthread_t* pthr_null(pthread_t* tp){  /*    * This should have the same effect as memset(tp, 0, sizeof(pthread_t))   * We're just showing that we can do it.   */  void* p = (void*) pthread_normalize(tp);  return (pthread_t*) bitclear(p, p, sizeof(pthread_t));}/* * Safe user-level pthr_compare function - modifies temporary thread handle copies */int pthr_compare_safe(pthread_t thread1, pthread_t thread2){  return memcmp(pthread_normalize(&thread1), pthread_normalize(&thread2), sizeof(pthread_t));}/* * Fast user-level pthr_compare function - modifies origin thread handles */int pthr_compare_fast(pthread_t* thread1, pthread_t* thread2){  return memcmp(pthread_normalize(&thread1), pthread_normalize(&thread2), sizeof(pthread_t));}/* * Safe user-level pthr_hash function - modifies temporary thread handle copy */hash_t pthr_hash_safe(pthread_t thread){  return hash((void *) pthread_normalize(&thread), sizeof(pthread_t));}/* * Fast user-level pthr_hash function - modifies origin thread handle */hash_t pthr_hash_fast(pthread_t thread){  return hash((void *) pthread_normalize(&thread), sizeof(pthread_t));}/* User-level bitclear function - modifies the origin array */void* bitclear(void* loc, void* mask, size_t count){  int i;  for (i=0; i < count; i++) {    (unsigned char) *loc++ &= ~((unsigned char) *mask++);  }}/* Donald Knuth hash */hash_t hash(void* str, size_t count){   hash_t hash = (hash_t) count;   unsigned int i = 0;   for(i = 0; i < len; str++, i++)   {      hash = ((hash << 5) ^ (hash >> 27)) ^ (*str);   }   return hash;}/* Example of advantage point (3) - split a thread handle into its id and non-id values */pthread_t id = thread, non-id = thread;bitclear((void*) &non-id, (void*) pthread_normalize(&id), sizeof(pthread_t));A pthread_t type change proposal to neutralise the effects of paddingEven if pthread_nornalize() is available, padding is still a problem becausethe standard only garrantees element-by-element equivalence throughcopy operations (assignment and pass-by-value). So padding bit values canstill change randomly after calls to pthread_normalize().[I suspect that most compilers take the easy path and always byte-copy anyway,partly because it becomes too complex to do (e.g. unions that contain sub-aggregates)but also because programmers can easily design their aggregates to minimise andoften eliminate padding].How can we eliminate the problem of padding bytes in structs? Coulddefining pthread_t as a union rather than a struct provide a solution?In fact, the Linux pthread.h defines most of it's pthread_*_t objects (but notpthread_t itself) as unions, possibly for this and/or other reasons. We'llborrow some element naming from there but the ideas themselves are well known- the __align element used to force alignment of the union comes from K&R'sstorage allocator example./* Essentially our current pthread_t renamed */typedef struct {  struct thread_state_t * __p;  long __x; /* sequence counter */} thread_id_t;Ensuring that the last element in the above struct is a long ensures that theoverall struct size is a multiple of sizeof(long), so there should be no trailingpadding in this struct or the union we define below.(Later we'll see that we can handle internal but not trailing padding.)/* New pthread_t */typedef union {  char __size[sizeof(thread_id_t)]; /* array as the first element */  thread_id_t __tid;  long __align;  /* Ensure that the union starts on long boundary */} pthread_t;This guarrantees that, during an assignment or pass-by-value, the compiler copiesevery byte in our thread_id_t because the compiler guarrantees that the __sizearray, which we have ensured is the equal-largest element in the union, retainsequivalence.This means that pthread_t values stored, assigned and passed by value will at leastcarry the value of any undefined padding bytes along and therefore ensure thatthose values remain consistent. Our comparisons will return consistent results andour hashes of [zero initialised] pthread_t values will also return consistentresults.We have also removed the need for a pthread_null() function; we can initialiseat declaration time or easily create our own const pthread_t to use in assignmentslater:const pthread_t null_tid = {0}; /* braces are required */pthread_t t;...t = null_tid;Note that we don't have to explicitly make use of the __size array at all. It'sthere just to force the compiler behaviour we want.Partial solutions without a pthread_normalize functionAn application-level pthread_null and pthread_compare proposal(and pthread_hash proposal by extention)In order to deal with the problem of scalar/aggregate pthread_t type disparity inportable code I suggest using an old-fashioned union, e.g.:Contraints:- there is no padding, or padding values are preserved through assignment and  pass-by-value (see above);- there are no extra non-id values in the pthread_t.Example 1: A null initialiser for pthread_t variables...typedef union {    unsigned char b[sizeof(pthread_t)];    pthread_t t;} init_t;const init_t initial = {0};pthread_t tid = initial.t; /* init tid to all zeroes */Example 2: A comparison function for pthread_t valuestypedef union {   unsigned char b[sizeof(pthread_t)];   pthread_t t;} pthcmp_t;int pthcmp(pthread_t left, pthread_t right){  /*  * Compare two pthread handles in a way that imposes a repeatable but arbitrary  * ordering on them.  * I.e. given the same set of pthread_t handles the ordering should be the same  * each time but the order has no particular meaning other than that. E.g.  * the ordering does not imply the thread start sequence, or any other  * relationship between threads.  *  * Return values are:  * 1 : left is greater than right  * 0 : left is equal to right  * -1 : left is less than right  */  int i;  pthcmp_t L, R;  L.t = left;  R.t = right;  for (i = 0; i < sizeof(pthread_t); i++)  {    if (L.b[i] > R.b[i])      return 1;    else if (L.b[i] < R.b[i])      return -1;  }  return 0;}It has been pointed out that the C99 standard allows for the possibility thatinteger types also may include padding bits, which could invalidate the abovemethod. This addition to C99 was specifically included after it was pointedout that there was one, presumably not particularly well known, architecturethat included a padding bit in it's 32 bit integer type. See section 6.2.6.2of both the standard and the rationale, specifically the paragraph starting atline 16 on page 43 of the rationale.An asideCertain compilers, e.g. gcc and one of the IBM compilers, include a featureextention: provided the union contains a member of the same type as theobject then the object may be cast to the union itself.We could use this feature to speed up the pthrcmp() function from example 2above by casting rather than assigning the pthread_t arguments to the union, e.g.:int pthcmp(pthread_t left, pthread_t right){  /*  * Compare two pthread handles in a way that imposes a repeatable but arbitrary  * ordering on them.  * I.e. given the same set of pthread_t handles the ordering should be the same  * each time but the order has no particular meaning other than that. E.g.  * the ordering does not imply the thread start sequence, or any other  * relationship between threads.  *  * Return values are:  * 1 : left is greater than right  * 0 : left is equal to right  * -1 : left is less than right  */  int i;  for (i = 0; i < sizeof(pthread_t); i++)  {    if (((pthcmp_t)left).b[i] > ((pthcmp_t)right).b[i])      return 1;    else if (((pthcmp_t)left).b[i] < ((pthcmp_t)right).b[i])      return -1;  }  return 0;}Result thus farWe can't remove undefined bits if they are there in pthread_t already, but we haveattempted to render them inert for comparison and hashing functions by making themconsistent through assignment, copy and pass-by-value.Note: Hashing pthread_t values requires that all pthread_t variables be initialisedto the same value (usually all zeros) before being assigned a proper thread ID, i.e.to ensure that any padding bits are zero, or at least the same value for allpthread_t. Since all pthread_t values are generated by the library in the firstinstance this need not be an application-level operation.ConclusionI've attempted to resolve the multiple issues of type opacity and the possiblepresence of undefined bits and bytes in pthread_t values, which preventapplications from comparing or hashing pthread handles.Two complimentary partial solutions have been proposed, one an application-levelscheme to handle both scalar and aggregate pthread_t types equally, plus adefinition of pthread_t itself that neutralises padding bits and bytes bycoercing semantics out of the compiler to eliminate variations in the values ofpadding bits.I have not provided any solution to the problem of handling extra values embeddedin pthread_t, e.g. debugging or trap information that an implementation is entitledto include. Therefore none of this replaces the portability and flexibility of APIfunctions but what functions are needed? The threads standard is unlikely toinclude that can be implemented by a combination of existing features and moregeneric functions (several references in the threads rationale suggest this.Therefore I propose that the following function could replace the several functionsthat have been suggested in conversations:pthread_t * pthread_normalize(pthread_t * handle);For most existing pthreads implementations this function, or macro, would reduce toa no-op with zero call overhead.

4 QueueUserAPCEx编译

由于VS2013 + WDK 8.1 Update编译驱动的方式我还没有搞清楚,以后补上。

5 pthread通用初始化头文件

对于pthread_win32的使用我提供一个通用的初始化文件“cruise_ptw32_static_init.h”,如下
#ifndef CRUISE_PTW32_STATIC_INIT_H#define CRUISE_PTW32_STATIC_INIT_H#ifdef PTW32_STATIC_LIB#include <cstdlib>#include <pthread.h>#endifstatic void ptw32_enable_cancel(void){#ifdef PTW32_STATIC_LIBpthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);#endif}#define CRUISE_PTW32_ENABLE_CANCEL(){ptw32_enable_cancel();}static void ptw32_attach(void){#ifdef PTW32_STATIC_LIB    pthread_win32_process_attach_np();    pthread_win32_thread_attach_np();#endif}static void ptw32_detach(void){#ifdef PTW32_STATIC_LIB    pthread_win32_thread_detach_np();    pthread_win32_process_detach_np();#endif}#if defined(_WIN32) && defined(PTW32_STATIC_LIB) #define CRUISE_PTW32_INIT()\{\attach_ptw32();\atexit((P_ATEXIT_PROC)detach_ptw32);\}#else#define CRUISE_PTW32_INIT()#endif#endif // CRUISE_PTW32_STATIC_INIT_H

6 参考资料

pthread学习
http://www.cppblog.com/saha/articles/189802.html
pthread_win32下的 pthread_t与posix的pthread_t的不同
http://www.cnblogs.com/ayanmw/archive/2012/08/07/2626661.html
pthread 静态编译版本在Windows下使用时的注意事项
http://blog.csdn.net/psusong/article/details/5189659
64位win7 vs2010 pthread的配置 - - ITeye技术网站
http://houyingsoft.iteye.com/blog/1907670
跨平台多线程
http://shenan1984.blog.163.com/blog/static/2530851020098231001787/
QueueUserAPCEx版本2:真正的异步通知用户模式在Windows平台上
http://www.orcode.com/article/Processes_20117249.html
跨平台多线程编程-fychit-ChinaUnix博客
http://blog.chinaunix.net/uid-20776117-id-1847029.html
跨平台多线程库pthread
http://blog.csdn.net/yinyhy/article/details/10959997
pthread-win32静态库的编译和使用方法
http://download.csdn.net/detail/eugenelyq/3604896
/MinGW/Base/pthreads-w32/pthreads-w32-2.9.0-pre-20110507-2
http://sourceforge.net/projects/mingw/files/MinGW/Base/pthreads-w32/pthreads-w32-2.9.0-pre-20110507-2/
0 0
原创粉丝点击