Multithreading:
1. The dynamic library has only one export function:
This situation is rare and is the easiest to handle. In this case, when writing a function, you only need to consider not to have conflicting global data. The global data includes the data blocks allocated in the heap and static global variables. If such global data exists, access to this function by different threads in the process may cause a conflict.
The solution is also very simple, that is, to use stacks as much as possible to solve the problem. Because the stack owner is a thread, it must be thread-safe. Of course, avoid stack overflow.
We all know that if you want to retain the status of the previous call when the function is called again, you can use static variables. But if you want to keep the thread security of the function, static variables cannot be used, because static variables are global and belong to processes, that is, they are shared by threads in processes. Therefore, if you really need to maintain the function state in the same thread, it is equivalent to passing parameters between different calls, you can consider using static global thread local variables, that is:
_ Declspec (thread) int tls_ I = 1;
This variable makes the compiler ensure that tls_ I corresponds to each thread, that is, each thread has a copy of tls_ I, Which is thread security.
2. Multiple Functions are exported from the dynamic library, and data transmission exists between multiple functions.
As mentioned above, DLL exports multiple functions, one initialization, one resource release, and the others are core function functions. Data transmission is very likely between these functions. If an initialization function is called in thread a and the core function is called in thread B, the resources of the initialization function of thread a cannot correspond to the core function of thread B, in addition, there is data transmission between core function functions. Such DLL is NOT thread-safe and will inevitably lead to errors.
The solution is that the user (that is, the person who uses the DLL) ensures that these export functions are called in a thread. However, this will greatly limit the interface design and the user's degree of freedom. Therefore, the best way is to manage the thread security of the function. Dynamic TLS and local thread storage are used for data transmission by different functions.
For example:
I have defined a global variable to store the index ID of the local storage of the current thread.
_ Declspec (thread) int tls_ I = 1;
When you call the function for resource allocation, call the dynamic TLS function tlsalloc, assign an ID, and record it in the global thread-safe tls_ I variable, the tlssetvalue function is used to store data in the thread-safe area. When the function to obtain resources is called, The tlsgetvalue function is used to obtain the resources. After the processing is complete, the tlsfree function is called to release TLS indexes, to occupy new threads.
In this way, as long as each function in the DLL ensures its local thread security, the entire DLL thread security can be realized by passing data between functions through TLS (static and dynamic.
3. restrict the number of threads used to access a function in the DLL.
Sometimes, there is a limit on the number of access threads for a function in the DLL. When the limit is exceeded, other threads have to wait for a certain period of time. If the execution opportunity cannot be obtained after a certain period of time, then return timeout. This design is user-friendly and practical for users. Some commercial programs are indeed priced based on the number of channels that allow users to access.
This encapsulation of the functions in the DLL is generally a simple semaphore to be used. When the DLL is initialized, The createsemaphore function is called to initialize the semaphore. Its prototype is as follows:
Handle createsemaphore (
Lpsecurity_attributes l1_maphoreattributes,
// Pointer to security attributes
Long linitialcount, // initial count
Long lmaximumcount, // maximum count
Lptstr lpname // pointer to semaphore-Object Name
);
For semaphores, the value of its status (an integer) is reduced by 1 every time the waitforsingleobject is waitforleobject (of course, it is required to enter). After releasesemaphore is used, the value of its status is increased by 1, when its status value is 0, the semaphore changes from a signal to no signal. With this feature of semaphores, we set the initial semaphores (2nd parameters) as the limited number of thread accesses during initialization. Within the function to limit the number of threads, call waitforsingleoject to obtain control and specify a wait time (specified by the configuration file). The function returns a response based on timeout, when releasesemaphore is used, other threads can call this function.
4. multi-thread security DLL under multi-process conditions.
As mentioned in the previous 3, sometimes the access thread of a function needs to be restricted. We know that dll can be loaded and called by multiple threads. That is to say, if we only restrict one process, this restriction can be easily cracked when multiple processes are called.
We all know that semaphore semaphores belong to kernel objects, that is, they can be shared and accessed by multiple processes. That is to say, if we specify a name for a semaphore, in another process, you only need to call the opensemaphore function to open the semaphore with the same name. So the problem is solved?
The reality is that in multi-process situations, it is generally not a simple multi-process to share a semaphore. Multi-process communication requires a lot of information. The general solution is to use shared data segments.
# Pragma data_seg ("share ")
Int performance_data;
# Pragma data_seg ()
# Pragma comment (linker, "/section: Share, RWS ")
A shared data segment named share is generated through the pragam compiler command, so that the variable pai_data can be shared by multiple processes. To exchange data between multiple processes, you only need to add a data definition to data_seg.
Create multiple threads in the mfc dll:
In addition to the initialization process, as long as the mfc dll uses the Win32 Thread Local Storage Area (TLS) function such as tlsalloc to allocate the thread local storage area, you can safely create multiple threads. However, if the mfc dll uses _ declspec (thread) to allocate the local storage area of the thread, the client application must be implicitly linked to the DLL. If the client application is explicitly linked to the DLL, the call to loadlibrary will not load the DLL.
For the reason, refer to Microsoft's article "PRB: Calling loadlibrary () to load a DLL that has static TLS". Address: http://support.microsoft.com/kb/118816/en-us.
The mfc dll that creates a new MFC thread during startup will be suspended when it is loaded by the application. This happens whenever afxbeginthread or cwinthread: createthread is called inside the following objects to create a thread:
Initinstance of the cwinapp derived object in Rule DLL.
The dllmain or rawdllmain functions provided by the rule DLL.
Extend the dllmain or rawdllmain functions provided by DLL.
For the reason, refer to the article "PRB: cannot create an MFC thread during DLL startup", http://support.microsoft.com/kb/142243/en-us.
Solution: Regular DLLs that create threads shoshould only do so in functions exported from the DLL and called by client applications. the recommended solution for MFC DLLs that need to create a thread when the DLL starts is to add a specific exported Initialization
Function and create the thread in it. (to create a multi-threaded rule DLL, you can only put the function of the startup thread into the export function, which is called and executed by the client. The thread cannot be automatically created during the DLL startup .)
Certificate ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Article transferred from: http://bbs.51cto.com/thread-513440-1.html