en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en nl en en en en en de fr en en en en nl en en en en en en en en en en en en nl en en en en en en fr en da en en en en en en en nl en en en en en en fr en en en en en en en nl en en en en en en en en en en en en nl en en en en en en en es en en en en nl vi en en fr en en en en en en en en en nl en en en en fr en en en en en en en en en en nl fr en en en en en en fr en en es en en en en nl en en it en en en en en en en en en en en en en en en en en en en en en en en en nl en en en en en en en fr en da en en en en en en en nl en en en en hbs_lat en en en en en en en nl en en en en en en en en en fr en da en en en en en en en nl en en en en en en en en en en en en nl en en en en en en en en en en en fr en da en en en en en en en nl en en en en en en en en en en en en en nl en en en en en en en en en en en en en fr en da en en en en en en en nl en en en en en en en en en en en en en en nl de en en en en en en en fr en da en en en en en en en nl en en en en en en en en en de en en en fr en en en en en en en en en pt en en en en en en
By logging into your account, you agree to our Privacy Policy, personal data processing and storage practices as described therein.
Forgot password or user name?
Search in titles only Search in PowerBASIC for Windows only
You are not logged in. You can browse in the PowerBASIC Community, but you must click Login (top right) before you can post. If this is your first visit, check out the FAQ or Sign Up.
All Time Today Last Week Last Month
All Discussions only Photos only Videos only Links only Polls only Events only
Previous 1 2 template Next
To be thread-safe, you cannot use Global or Static variables...
My old problem has returned. A customer wants to use my DLL in a web application and his web application test program, written in .net, shows him that he can not call the DLL from more than one thread without getting error messages like
"Exception of type 'System.AccessViolationException' occurred in thread 'Thread3'.
The exception message was 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'."
As his test program works with similar DLLs from other companies he wants to know if I am sure my DLL is thread-safe. The problem is I do not know. I know that I am not using threads in the DLL but are there other things that can make a DLL "thread-unsafe"?
I would simply avoid global vars and additionally let the dll be invoked only once by controlling the static value of a thread counter in LIBMAIN.
Last edited by norbert doerre; 18 Sep 2010, 03:11 PM.
Join Date: Aug 2005
18 Sep 2010, 04:14 PM
Were threaded variables available last time you came this way?
From the PB help on THREADED VARIABLES:
Thread variables have a distinct advantage over global variables as they avoid the need to use synchronization techniques (such as a Critical Section object or Mutex) when referencing (reading or writing) from two or more threads at the same time. In addition, all allocation and deallocation of THREADED memory is handled automatically by PowerBASIC without any need for intervention by the programmer. However, by their nature, thread variables impose a slight, yet measurable, performance penalty as compared to other variable types.
Join Date: Feb 2005
18 Sep 2010, 06:28 PM
Did you use any of these statements?
FREEFILE (not sure if it was thread safe in that version.)
Join Date: Aug 2005
18 Sep 2010, 08:04 PM
Originally posted by Mike Doty View Post
Did you use any of these statements?
FREEFILE (not sure if it was thread safe in that version.)
In addition is your DLL using any external functions (Windows or third party DLL) that are not thread safe?
Join Date: Feb 1999
19 Sep 2010, 06:38 AM
The core of the DLL is code written in the seventies by a colleague of mine, now retired, using DEC basic.
The code was then ported to Quick Basic and then to Visual Basic with only the changes needed to get it through the compilers. Finally I was involved in the last step to port it to a PB DLL and I have added lot of code the last 10 years.
In the old core code there is a lot of STATIC and GLOBAL declarations that I have no idea if they are needed (if you saw the code you should understand why).
But if I understand your advice I must replace them if the DLL should be thread-safe. I will have to replace them one by one and see if the DLL still gives the correct results.
The DLL is not using any external functions.
Join Date: Feb 2005
19 Sep 2010, 09:06 AM
0 = No protection of globals
1 = Use Critical Section
2 = Use THREADED variable
Notice the DLL automatically initializes/deletes a critical section in LIBMAIN.
If needed, change to 0: %THREADED_STATEMENT_SUPPORTED = 1
With a GLOBAL the gCounter is not reset to 0 with a new thread.
With a THREADED variable the tCounter is unique for each thread.
If another program/process loads the DLL it gets a new set of variables.
Hope this may be of some use.
#COMPILE DLL "MyDLL.DLL" #INCLUDE "win32api.inc" '--------------------------------------------------------------------------- %THREADED_STATEMENT_SUPPORTED = 1 ' DECLARE FUNCTION Bump LIB "MyDll.Dll"(Action AS LONG) AS LONG DECLARE SUB EnterCritical LIB "MyDll.Dll" DECLARE SUB LeaveCritical LIB "MyDll.Dll" '--------------------------------------------------------------------------- GLOBAL gCS AS CRITICAL_SECTION GLOBAL gcounter AS LONG '--------------------------------------------------------------------------- #IF %THREADED_STATEMENT_SUPPORTED THREADED tCounter AS LONG #ENDIF '--------------------------------------------------------------------------- SUB EnterCritical EXPORT 'start protection EnterCriticalSection gCS END SUB '--------------------------------------------------------------------------- SUB LeaveCritical EXPORT 'end protection LeaveCriticalSection gCs END SUB '--------------------------------------------------------------------------- FUNCTION Bump(Action AS LONG) EXPORT AS LONG LOCAL value AS LONG IF Action   2 THEN INCR gCounter FUNCTION = gCounter ELSE #IF %THREADED_STATEMENT_SUPPORTED INCR tCounter FUNCTION = tCounter #ELSE FUNCTION = -123456 #ENDIF END IF END FUNCTION '--------------------------------------------------------------------------- #IF %THREADED_STATEMENT_SUPPORTED FUNCTION tBump EXPORT AS LONG INCR tCounter 'modified after posting FUNCTION = tCounter END FUNCTION #ENDIF '--------------------------------------------------------------------------- FUNCTION LIBMAIN(BYVAL hInstance AS DWORD, _ BYVAL lReason AS LONG, _ BYVAL lReserved AS LONG) AS LONG SELECT CASE AS LONG lReason CASE %DLL_PROCESS_ATTACH InitializeCriticalSection gCS 'critical section automatically allocated ? "InitializeCriticalSection" LIBMAIN = 1 EXIT FUNCTION CASE %DLL_PROCESS_DETACH DeleteCriticalSection gCS 'critical section automatically allocated ? "DeleteCriticalSection EXIT FUNCTION CASE %DLL_THREAD_ATTACH EXIT FUNCTION CASE %DLL_THREAD_DETACH EXIT FUNCTION END SELECT LIBMAIN = 0: ? "failure to initialize the DLL! END FUNCTION
Program to test DLL:
#DIM ALL '--------------------------------------------------------------------------- DECLARE FUNCTION Bump LIB "MyDll.Dll"(Action AS LONG) AS LONG DECLARE SUB EnterCritical LIB "MyDll.Dll" DECLARE SUB LeaveCritical LIB "MyDll.Dll" '--------------------------------------------------------------------------- FUNCTION PBMAIN () AS LONG LOCAL hThread AS DWORD LOCAL sInput AS STRING LOCAL ThreadsWanted AS LONG LOCAL Counter AS LONG LOCAL sChoices AS STRING sChoices = "0=Global without protection" + $CR + _ "1=Global with Critical Section" + $CR + _ "2=Threaded variable" sInput = "1" ThreadsWanted = 4 '2 or more DO sInput = INPUTBOX$(sChoices,"Message boxes will be" + STR$(ThreadsWanted),sInput,0,300) IF INSTR("012",sInput) = 0 THEN ? "Please enter 0 - 2":ITERATE IF LEN(sInput) = 0 THEN EXIT DO FOR counter = 1 TO ThreadsWanted THREAD CREATE DLLTESTER(VAL(sInput)) TO hThread THREAD CLOSE hThread TO hThread NEXT LOOP END FUNCTION '--------------------------------------------------------------------------- FUNCTION DLLTESTER(BYVAL Action AS LONG) AS LONG LOCAL counter AS LONG LOCAL s AS STRING LOCAL FromDLL AS LONG LOCAL sTitle AS STRING IF Action = 1 THEN EnterCritical FOR counter = 1 TO 10 FromDll = Bump(Action) s = s + FORMAT$(FromDLL)+ $CR IF counter MOD 10 THEN SLEEP 0 NEXT IF Action = 1 THEN LeaveCritical IF Action = 0 THEN sTitle = "Global without protection" IF Action = 1 THEN sTitle = "Global with Critical Section" IF Action = 2 THEN sTitle = "THREADED variable" ? s + $CR + "Thread ends here",,sTitle END FUNCTION
Last edited by Mike Doty; 19 Sep 2010, 09:31 AM. Reason: FUNCTION = tCounter + 1 should have been INCR tCounter:FUNCTION = tCounter
Join Date: Aug 1998
19 Sep 2010, 03:52 PM
FWIW, DLLs are not thread-safe, or not thread-safe.
Procedures are thread-safe or not thread-safe.
Port Washington WI USA
Join Date: Aug 2005
20 Sep 2010, 05:25 PM
Originally posted by michael mattias View Post
threadsafe or not threadsafe
Join Date: Aug 1998
20 Sep 2010, 05:47 PM
I knew that sounded funny.
Let's try it with single quotes....
Procedures are 'thread-safe' or 'not thread-safe.'
That is, a procedure is either thread-safe or it isn't.
As contrasted with "A DLL is either thread safe or it isn't" because "Thread-safeness" is NOT an attribute of a dynamic link library; "thread-safeness" is an attribute of a procedure.
Port Washington WI USA
Join Date: Feb 2000
21 Sep 2010, 08:19 AM
I don't believe that is correct MCM as the Thread Safe Variables as offered by PB are actually set up in the DLL at the time the thread attaches the DLL i.e. at a %DLL_THREAD_ATTACH in LIBMAIN not in the procedure. This means that such variables are GLOBAL to the thread and unique to the thread. I suspect PB actually uses an underlying feature built into Windows exactly for this purpose and takes care of the extra indirection (pointer level) for us.
Thus the basic concept of a "thread safe DLL" is truly at the DLL level and not the procedure level.
Of course it is still very easy for a programmer to make the thread unsafe by incorrect handling of application wide Globals an procedure Statics
Join Date: Aug 1998
21 Sep 2010, 08:42 AM
> don't believe that is correct MCM as the Thread Safe Variables as offered by PB are
Actually my statement is correct, but I never got into implementation.
But even if we do get into implementation....
"The use of THREADED variables can make your procedures thread-safe."
I suppose you could say that if all the procedures in your DLL are thread-safe, then your DLL is thread-safe... but that smacks too much of Clintonian parsing for my taste.
FWIW, THREADED variables are currently implemented by PB using Thread Local Storage. If you are interested in just how much easier THREADED variables have made using TLS, check out this "before there were THREADED variables" demo.... Terminate Worker Threads Using Windows Events (and Using Thread Local Storage) Demo Dec 23 2005 .
Port Washington WI USA
Join Date: Feb 2000
21 Sep 2010, 09:20 AM
MCM can I lend you my glasses? This post thread is about DLL's. Your example does not A have a DLL and B doesn't show how to use the intrinsic thread safe methods for variable that were built into Windows long before your examples using slow synchonization. PB does not use the slow methods you keep posting.
You reall do need to get up to date.
Can't quickly find the Microsoft documentation but from memory a poor description of the process is that Windows guarantees in the paging system to provide a separate area for each thread to store its own global variables which are accessed via the thread number (actually just an extension of the DLL philosophy)
I don't know just how much extra work the PB compiler has to do to use this feature, nor do I care. It works and it is fast>
Join Date: Aug 1998
21 Sep 2010, 05:02 PM
>This post thread is about DLL's. Your example does not A have a DLL
Of course my demo doesn't have a DLL THREAD-SAFENESS HAS **NOTHING** TO DO WITH THE FACT A PROCEDURE DOES OR DOES NOT LOAD FROM A DYNAMIC LINK LIBRARY.
THAT'S THE WHOLE POINT!! "DLL" is moot!!!
and B doesn't show how to use the intrinsic thread safe methods for variable that were built into Windows long before your examples using slow synchonization
You mean the interlocked functions?
First off, you don't use the Interlocked functions for the same purpose you'd use Thread Local Storage.
Next.. no, I didn't bother creating a demo for the use of the Interlocked functions.
I figured my time was better spent doing some of the more advanced stuff. But you can go ahead and create a demo of the interlocked functions. Post here if you need help.
Port Washington WI USA
Join Date: Feb 2000
22 Sep 2010, 08:24 AM
MCM so just where in your demo do you use the TlsAlloc, TlsFree, TlsSetValue, or TlsGetValue functions.
Do you know what they do? Do you know how to apply them in a DLL (as that is the subject of this thread)?
Fortunately for us PB does understand.
PS they became available in 2000
Last edited by John Petty; 22 Sep 2010, 08:26 AM.
Join Date: Aug 1998
22 Sep 2010, 08:33 AM
>Do you know how to apply them in a DLL (as that is the subject of this thread)?
There IS no difference in the use of the Tlsxxxx functions based on where the procedure in which they are used is located.
Procedures which happen to be located in a DLL, once DECLAREd in the calling module, may as well have been #INCLUDED in source code format in that calling module, with only variable scope excepted.
Port Washington WI USA
Join Date: Feb 2000
22 Sep 2010, 03:16 PM
MCM you still don't get it, so I will try again for the sake of th OP. A DLL does not care what language it is called by or if the caller is multithreaded how well that was written. Of course it must assume any variables passed to it are thread safe (your point about procedures). However if the DLL maintains any state information i.e last time thread 1 called this exported function It returned item 3 from list A so next time it should given item 4 from list A, meanwhile last time thread 2 retrieved item 6 from list B so next time should be given item 7 from list B. Another example, one exported function in the DLL uses many internal other functions with possible static and global variables so that threads use of the DLL could be switched out in the middle of processing and another thread use the DLL.
For either of these reasons the DLL may require its own Thread Local Storage as well as the calling procedure, thus the TlsAlloc is done in DLLMain not the procedure as that is the time it knows it has been called by a new thread.
For the OP threaded variables became available in 8.03.
Previous 1 2 template Next
Copyright © 1998-2022 PowerBASIC Tools, LLC - All Rights Reserved.
Powered by vBulletin® Version 5.7.0
Copyright © 2022 vBulletin Solutions, Inc. All rights reserved.
All times are GMT-5. This page was generated at 04:29 AM.
We process personal data about users of our site, through the use of cookies and other technologies, to deliver our services, and to analyze site activity. For additional details, refer to our Privacy Policy.
By clicking "I AGREE" below, you agree to our Privacy Policy and our personal data processing and cookie practices as described therein. You also acknowledge that this forum may be hosted outside your country and you consent to the collection, storage, and processing of your data in the country where this forum is hosted.