user-0 提问: C++多个线程调用同一个dll中的一个函数，怎么知道有多少个线程同时进入了这个函数体

回复:
user: user-1
content: HANDLE CreateSemaphore(    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,                         // pointer to security attributes    LONG lInitialCount,  // initial count    LONG lMaximumCount,  // maximum count    LPCTSTR lpName       // pointer to semaphore-object name  );  用Semaphore控制线程访问的个数。

user: user-2
content: 引用 15 楼 truexf 的回复:有限的访问是同时只允许一个线程调用？还是可以允许有限的n个调用？ 如果是前者，用临界区控制。如果是后者，用信号量控制。 以上建议只针对windows平台。

user: user-2
content: 有限的访问是同时只允许一个线程调用？还是可以允许有限的n个调用？

user: user-3
content: 引用 10 楼 yidaimu 的回复:[quote=引用 5 楼 justin_duan 的回复:] [quote=引用 3 楼 yidaimu 的回复:] 感谢您的回答。其实我在dll内部定义了一个static变量a=0，函数中打印++a的结果都是1。也就是没有达到计数的效果。有限资源的个数是dll控制的，所以没有采用在外部调用时限制线程的个数这种方式。这实际上像是一个子线程不通过父线程控制而达到同步的问题。 外部资源有源码吗？如果可以的话是不是能从外部资源控制一下访问数。 PS：打印++a说明当前时间函数也许没被调用啊- -怎么就确定是没计数效果呢，能否考虑做这么个试验，把DLL的函数修改下一直while(1)循环不结束函数再看看a的结果，我觉得在函数内设置一个static变量应该是有效的。 另外我猜你这个问题的需求应该是不想用临界区的，如果不用临界区处理的话我觉得最好还是能在调用端处理对dll的调用，省点心[/quote] 不是不想用临界区，是这个临界区需要dll（作为子线程）自己去维护。或者说有什么办法能让外部程序来维护这个临界区？ 另外，我之前++a在代码中写错地方了。我测试的结果是++a会是1-N（顺序不是递增，但数字不重复）。我还是有点担心数字会重复，毕竟我没有对++a做Lock操作。[/quote] 用mutex试试看？可以跨进程同步。我主要是没太搞明白你说的外部资源，是一个还是多个进程。

user: user-4
content: Critical Section Objects Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization. Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads.   The process is responsible for allocating the memory used by a critical section. Typically, this is done by simply declaring a variable of type CRITICAL_SECTION. Before the threads of the process can use it, initialize the critical section by using the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function.   A thread uses the EnterCriticalSection or TryEnterCriticalSection function to request ownership of a critical section. It uses the LeaveCriticalSection function to release ownership of a critical section. If the critical section object is currently owned by another thread, EnterCriticalSection waits indefinitely for ownership. In contrast, when a mutex object is used for mutual exclusion, the wait functions accept a specified time-out interval. The TryEnterCriticalSection function attempts to enter a critical section without blocking the calling thread.  Once a thread owns a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.  A thread uses the InitializeCriticalSectionAndSpinCount or SetCriticalSectionSpinCount function to specify a spin count for the critical section object. On single-processor systems, the spin count is ignored and the critical section spin count is set to 0. On multiprocessor systems, if the critical section is unavailable, the calling thread will spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.   Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.   When a critical section object is owned, the only other threads affected are those waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue running.

user: user-4
content: 纠正楼上： 临界区虽然不是跨进程的，但效率一般高于其它同步机制。

user: user-4
content: 临界区是跨进程的，且效率一般高于其它同步机制。 Synchronization Functions The following functions are used in synchronization.        CancelWaitableTimer   CreateEvent   CreateMutex   CreateSemaphore   CreateWaitableTimer   DeleteCriticalSection   EnterCriticalSection   GetOverlappedResult   InitializeCriticalSection   InitializeCriticalSectionAndSpinCount   InterlockedCompareExchange   InterlockedDecrement   InterlockedExchange   InterlockedExchangeAdd   InterlockedIncrement   LeaveCriticalSection   MsgWaitForMultipleObjects   MsgWaitForMultipleObjectsEx   OpenEvent   OpenMutex   OpenSemaphore   OpenWaitableTimer   PulseEvent   QueueUserAPC   ReleaseMutex   ReleaseSemaphore   ResetEvent   SetCriticalSectionSpinCount   SetEvent   SetWaitableTimer   SignalObjectAndWait   TimerAPCProc   TryEnterCriticalSection   WaitForMultipleObjects   WaitForMultipleObjectsEx   WaitForSingleObject   WaitForSingleObjectEx

user: user-0
content: 引用 5 楼 justin_duan 的回复:[quote=引用 3 楼 yidaimu 的回复:] 感谢您的回答。其实我在dll内部定义了一个static变量a=0，函数中打印++a的结果都是1。也就是没有达到计数的效果。有限资源的个数是dll控制的，所以没有采用在外部调用时限制线程的个数这种方式。这实际上像是一个子线程不通过父线程控制而达到同步的问题。 外部资源有源码吗？如果可以的话是不是能从外部资源控制一下访问数。 PS：打印++a说明当前时间函数也许没被调用啊- -怎么就确定是没计数效果呢，能否考虑做这么个试验，把DLL的函数修改下一直while(1)循环不结束函数再看看a的结果，我觉得在函数内设置一个static变量应该是有效的。 另外我猜你这个问题的需求应该是不想用临界区的，如果不用临界区处理的话我觉得最好还是能在调用端处理对dll的调用，省点心[/quote] 不是不想用临界区，是这个临界区需要dll（作为子线程）自己去维护。或者说有什么办法能让外部程序来维护这个临界区？ 另外，我之前++a在代码中写错地方了。我测试的结果是++a会是1-N（顺序不是递增，但数字不重复）。我还是有点担心数字会重复，毕竟我没有对++a做Lock操作。

user: user-4
content: 在DllMain中 fdwReason 为DLL_PROCESS_ATTACH时InitializeCriticalSection 为DLL_PROCESS_DETACH时DeleteCriticalSection

user: user-0
content: 引用 4 楼 zhao4zhong1 的回复:CRITICAL_SECTION cs;  InitializeCriticalSection(&cs);  int Limit4ThreadCalled() {     static DWORD ThreadIDs[4];     int it;     DWORD tid;     EnterCriticalSection(&cs);     tid=GetCurrentThreadId(VOID);     for (it=0;it<4;it++) {         if (ThreadIDs[it]==tid) break;         if (ThreadIDs[it]==0) {             ThreadIDs[it]=tid;             break;         }     }     LeaveCriticalSection(&cs);     if (it>=4) return 1;     //...      EnterCriticalSection(&cs);     ThreadIDs[it]=0;     LeaveCriticalSection(&cs);     return 0; }  DeleteCriticalSection(&cs);  CritialSection的初始化和释放的时机怎么控制呢？dll导出的只是一个函数（dll内部可以使用全局或是静态变量），不能在外部控制初始化和释放CritialSection吧。

user: user-5
content: 引用 3 楼 yidaimu 的回复:感谢您的回答。其实我在dll内部定义了一个static变量a=0，函数中打印++a的结果都是1。也就是没有达到计数的效果。有限资源的个数是dll控制的，所以没有采用在外部调用时限制线程的个数这种方式。这实际上像是一个子线程不通过父线程控制而达到同步的问题。 函数内部有static变量的，是不能重入的，即不能够用于多线程。因为二个线程同时让static 变量++。这样的结果是不确定的。并不能够++2次。

user: user-6
content: 信号量Semaphore...

user: user-3
content: 引用 3 楼 yidaimu 的回复:感谢您的回答。其实我在dll内部定义了一个static变量a=0，函数中打印++a的结果都是1。也就是没有达到计数的效果。有限资源的个数是dll控制的，所以没有采用在外部调用时限制线程的个数这种方式。这实际上像是一个子线程不通过父线程控制而达到同步的问题。 外部资源有源码吗？如果可以的话是不是能从外部资源控制一下访问数。 PS：打印++a说明当前时间函数也许没被调用啊- -怎么就确定是没计数效果呢，能否考虑做这么个试验，把DLL的函数修改下一直while(1)循环不结束函数再看看a的结果，我觉得在函数内设置一个static变量应该是有效的。 另外我猜你这个问题的需求应该是不想用临界区的，如果不用临界区处理的话我觉得最好还是能在调用端处理对dll的调用，省点心

user: user-4
content: CRITICAL_SECTION cs;  InitializeCriticalSection(&cs);  int Limit4ThreadCalled() {     static DWORD ThreadIDs[4];     int it;     DWORD tid;     EnterCriticalSection(&cs);     tid=GetCurrentThreadId(VOID);     for (it=0;it<4;it++) {         if (ThreadIDs[it]==tid) break;         if (ThreadIDs[it]==0) {             ThreadIDs[it]=tid;             break;         }     }     LeaveCriticalSection(&cs);     if (it>=4) return 1;     //...      EnterCriticalSection(&cs);     ThreadIDs[it]=0;     LeaveCriticalSection(&cs);     return 0; }  DeleteCriticalSection(&cs);

user: user-0
content: 感谢您的回答。其实我在dll内部定义了一个static变量a=0，函数中打印++a的结果都是1。也就是没有达到计数的效果。有限资源的个数是dll控制的，所以没有采用在外部调用时限制线程的个数这种方式。这实际上像是一个子线程不通过父线程控制而达到同步的问题。

user: user-7
content: 引用 1 楼 mgy4938 的回复:定义个全局变量了，记一下数当创建一个新线程的时候用一个变量来计数

user: user-8
content: 定义个全局变量了，记一下数

user: user-4
content: 引用 22 楼 go_and_see 的回复:[quote=引用 12 楼 zhao4zhong1 的回复:] 纠正楼上： 临界区虽然不是跨进程的，但效率一般高于其它同步机制。  哈哈，赵老师差点毁了俺的三观，好好及时纠正过来。 [/quote]

user: user-9
content: 引用 12 楼 zhao4zhong1 的回复:纠正楼上： 临界区虽然不是跨进程的，但效率一般高于其它同步机制。  哈哈，赵老师差点毁了俺的三观，好好及时纠正过来。

user: user-10
content: 既然是C++，那就在dll导出类里定义一个静态数据成员吧，这样不是很好吗？不要写全局变量，因为你做的是C++而不是C。