[threads] Unexpected behaviour of Thread loal storage
Hello, I would like to ask if there is everything ok with my way of thinking. I have 3 solutions (projects) in MS Visual Studio. Let say: SolutionA (static lib) SolutionB (linked with Solution A) SolutionC (linked with Solution A) In Header file of solutionA I have delaration of TLS from boost static boost::thread_specific_ptr<int> TLS; And now in SolutionB I set tls (TLS.reset(uVariable)) - uVariable is integer 2 Call function from SolutionC and call TLS.get() but there is different value than 2. But when i return from function to SolutionB and call TLS.get there is everything ok (return 2). It's ok ? Why in solutionC there is no visibilty of value set in solutionB ? It's the same thread (with the same threadId). Best regards
On Wed, Apr 29, 2015 at 10:07 AM, Fu ji
Hello,
I would like to ask if there is everything ok with my way of thinking.
I have 3 solutions (projects) in MS Visual Studio.
Let say:
SolutionA (static lib) SolutionB (linked with Solution A) SolutionC (linked with Solution A)
In Header file of solutionA I have delaration of TLS from boost
static boost::thread_specific_ptr<int> TLS;
And now in SolutionB I set tls (TLS.reset(uVariable)) - uVariable is integer 2
Call function from SolutionC and call TLS.get() but there is different value than 2.
But when i return from function to SolutionB and call TLS.get there is everything ok (return 2).
It's ok ? Why in solutionC there is no visibilty of value set in solutionB ? It's the same thread (with the same threadId).
Since SolutionA is a static lib, you basically have two different copies of TLS - one in each of the other two solutions that you link with SolutionA. On Windows there is no support for symbol relocation so the two copies continue to be independent after you load SolutionB and SolutionC binaries. Each of these two solutions work with its own copy and not the other. If you want to fix that you have to ensure there is only one instance of the TLS variable. One way to do that is to make SolutionA a shared library (dll).
Thank you for reply, I forget to say that solutionB and solutionC is also dll, so I decided to merge solutionA and SolutionC. Right now I have SolutionB and SolutionC (here is tls) both are dll. The same situation: SolutionB I set tls (TLS.reset(uVariable)) - uVariable is integer 2 Call function from SolutionC and call TLS.get() but there is different value than 2. But when i return from function to SolutionB and call TLS.get there is everything ok (return 2). But still no effect, where I made a mistake ?
On Wed, Apr 29, 2015 at 3:56 PM, Fu ji
Thank you for reply,
I forget to say that solutionB and solutionC is also dll, so I decided to merge solutionA and SolutionC. Right now I have SolutionB and SolutionC (here is tls) both are dll. The same situation:
SolutionB I set tls (TLS.reset(uVariable)) - uVariable is integer 2 Call function from SolutionC and call TLS.get() but there is different value than 2. But when i return from function to SolutionB and call TLS.get there is everything ok (return 2).
But still no effect, where I made a mistake ?
Is the TLS variable defined in a header which is included in both SolutionB and C?
Tls is in header in SolutionC. In solutionB there is only header with declaration: class __declspec( dllexport ) TLSslot;
Maybe it's because in solutionB I have delaration of tls (in other way I
have problem with building solution:
file.obj : error LNK2001: unresolved external symbol "public: static class
boost::thread_specific_ptrclassnamespace::CClass
namespace::CThreadLocalStorageSlot::ThreadLocalStorage_"
(?ThreadLocalStorage_@CThreadLocalStorageSlot@tnamespace@
@2V?$thread_specific_ptr@VCThread@namespace@@@boost@@A)
)
2015-04-29 15:18 GMT+02:00 Andrey Semashev
On Wed, Apr 29, 2015 at 4:13 PM, Fu ji
wrote: Tls is in header in SolutionC.
If that header is #included in SolutionB somewhere and TLS is defined in that header (e.g. with the static keyword, like in your initial post) then that variable is again duplicated in both solutions.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On Wed, Apr 29, 2015 at 4:40 PM, Fu ji
Maybe it's because in solutionB I have delaration of tls (in other way I have problem with building solution:
file.obj : error LNK2001: unresolved external symbol "public: static class boost::thread_specific_ptrclassnamespace::CClass namespace::CThreadLocalStorageSlot::ThreadLocalStorage_" (?ThreadLocalStorage_@CThreadLocalStorageSlot@tnamespace@ @2V?$thread_specific_ptr@VCThread@namespace@@@boost@@A)
)
You have to declare the TLS variable in the header, it has to have external linkage. Given that you have two dlls, it must also be exported. For example: // tls.h extern API boost::thread_specific_ptr<int> TLS; Then you have to define this object in one cpp file of SolutionC, like this: // tls.cpp #include "tls.h" API boost::thread_specific_ptr<int> TLS; Here API is a macro which is defined to __declspec(dllexport) when you build SolutionC and __declspec(dllimport) otherwise. PS: This is really not a Boost-related question. You need to understand how linking works on Windows in general.
Thank you for help Andrey but it's still not working. Right now I sipmlify it to minimum, in SolutionC (dll) in Include (tls.h) I have: extern __declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage; in the same soltuion but in Src i have tls.cpp with: __declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage; and this is ok, compile with any problems. SolutionB(dll) in file.pp I have: __declspec(dllimport) boost::thread_specific_ptr<int> ThreadLocalStorage; and right now I have a different issue, after compile, run I try to change value of tls in SolutionB in reset funtion I have assertion. Maybe you have some idea why ? Best regards and once again thank you for help.
On Thursday 30 April 2015 11:05:05 Fu ji wrote:
Thank you for help Andrey but it's still not working.
Right now I sipmlify it to minimum, in SolutionC (dll) in Include (tls.h) I have:
extern __declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage;
in the same soltuion but in Src i have tls.cpp with:
__declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage;
and this is ok, compile with any problems.
SolutionB(dll) in file.pp I have:
__declspec(dllimport) boost::thread_specific_ptr<int> ThreadLocalStorage;
and right now I have a different issue, after compile, run I try to change value of tls in SolutionB in reset funtion I have assertion. Maybe you have some idea why ?
No. What kind of assertion?
It was _Block_Type_Is_Valid (pHead->nBlockUse) Error, so I think it was double free and i fix it by all .release before .reset and it helps, but there is the same problem with double instance of tls.
Ok, I already now how weird tree I have in project. First there is run service.exe which load dispather.dll. Here I use function from mainlibrary.dll (there is reference mainlibrary in dispatcher properties). Now from mainlibrary (where is declaration of tls) I load module.dll, in this module I all function from dispather and reset tls with value = 2, back to module and try to get value from tls, but it looks like tls is not initialized with any value. There is a difference beetwen boost tls and tls from win api in this case ?
On Thursday 30 April 2015 14:06:15 Fu ji wrote:
There is a difference beetwen boost tls and tls from win api in this case ?
Boost.Thread TLS is based on the underlying OS API for TLS but it is not compatible. One essential point of difference is that Boost.Thread TLS identifies the pointer by its address (this is why duplicating the pointer breaks your case) while Windows TLS provides a key which can be copied.
I went back to problem, in header I have: extern __declspec(dllexport) boost::thread_specific_ptr<int> Storage; extern __declspec(dllexport) int tls_value_storage = 10; //for test In Src I have: extern __declspec(dllexport) boost::thread_specific_ptr<int> Storage; // Error extern __declspec(dllexport) int tls_value_storage; but here I have error in compiling process, there is ok if there is only declaration without extern (in other case I have error LNK1120: 1 unresolved externalsl). In other project I have: extern __declspec(dllimport) boost::thread_specific_ptr<int> TlxStorage; extern __declspec(dllimport) int tls_value_storage; and it's ok. Integer tls_value_storage is only for testing purpose, it work fine (I can see variable in other project). Thanks in advance.
I try to summing up all things:
I try to export thread local storage (dllexport)
from firstmodule and import in secondmodule (dllimport) but with no effect.
In firstmodule I have Includes/ThreadLocalStorage.h with delaration:
#include
On Wed, May 6, 2015 at 9:37 AM, Fu ji
I try to summing up all things:
I try to export thread local storage (dllexport) from firstmodule and import in secondmodule (dllimport) but with no effect. In firstmodule I have Includes/ThreadLocalStorage.h with delaration:
#include
namespace threads {
extern __declspec(dllexport) boost::thread_specific_ptr<int> TlsStorage; extern __declspec(dllexport) int tls_value_storage = 0;
}
integer tls_value_storage is for testing purpose only. There is also Src/ThreadLocalStorage.cpp with:
#include
namespace threads {
__declspec(dllexport) boost::thread_specific_ptr<int> TlsStorage; extern __declspec(dllexport) int tls_value_storage;
extern is not needed here, unless you want to define tls_value_storage elsewhere.
}
and the last one: in stdafx.h in secondmodule module:
namespace threads {
extern __declspec(dllimport) boost::thread_specific_ptr<int> TlsStorage; extern __declspec(dllimport) int tls_value_storage2; }
But after all when I try to change set tls in secondmodule
threads::TlsStorage.reset(&new_language_value); int *sanity_check = threads::TlxStorage.get(); //.get() return proper value
Funtion();
Now we go to the firstmodule, function() (using the same thread)
int sanity_check_1 = threads::tls_value_storage; //Proper value int *sanity_check_2 = threads::TlsStorage.get(); // Something bad happens, return uninitialized tls
Do you link to Boost.Thread built as a shared library (dll)? Both libraries must use Boost.Thread dll because it maintains a global list of thread_specific_ptr storage objects internally.
I think it can be fault of missing extern before __declspec(dllexport) boost::thread_specific_ptr<int> TlsStorage in ThreadLoalStorage.cpp but when I add "extern" I have:
error LNK2001: unresolved external symbol "__declspec(dllimport) class boost::thread_specific_ptr<int> threads::TlsStorage" (__imp_?TlsStorage@threads@tlx@@3V?$thread_specific_ptr@H@boost@@A)
in compiling process. Maybe it's some issue with mangling ?
When you write extern you declare the object which must be defined elsewhere. There must be exactly one definition of the object (without extern), so you would typically declare it in a header (for reuse by other source files) and define in a cpp file. The error says that you provided no definition of the TlsStorage object (because you added the extern keyword, changing the definition into a declaration).
Do you link to Boost.Thread built as a shared library (dll)? Both libraries must use Boost.Thread dll because it maintains a global list of thread_specific_ptr storage objects internally.
This could be a problem, in both solutions I have in Properties: Additional Include Directories: ..\3rdParty\Common\include\boost (here I have .hpp files) and in Linker: Additional Library Directories: ..\3rdParty\$(Platform)\VC12\lib and here I have libboost_thread-vc120-mt-1_57.lib May I do this in some other way ? I read that I can achieve that by define: #define BOOST_ALL_DYN_LINK in pre-compiled header stdafx.h Thank you for your patience Andrey.
On Wed, May 6, 2015 at 11:25 AM, Fu ji
Do you link to Boost.Thread built as a shared library (dll)? Both libraries must use Boost.Thread dll because it maintains a global list of thread_specific_ptr storage objects internally.
This could be a problem, in both solutions I have in Properties:
Additional Include Directories: ..\3rdParty\Common\include\boost (here I have .hpp files)
and in Linker: Additional Library Directories: ..\3rdParty\$(Platform)\VC12\lib and here I have libboost_thread-vc120-mt-1_57.lib
I don't use Windows but AFAIR the library name should be something like boost_thread-vc120-mt-1_57.lib (note no leading 'lib') and a similarly named dll. If you don't have these you will have to rebuild boost. Make sure you add 'link=shared' to b2 command line.
May I do this in some other way ? I read that I can achieve that by define: #define BOOST_ALL_DYN_LINK in pre-compiled header stdafx.h
Yes, BOOST_ALL_DYN_LINK must be defined when you build both your libraries.
On Thursday 30 April 2015 11:05:05 Fu ji wrote:
Thank you for help Andrey but it's still not working.
Right now I sipmlify it to minimum, in SolutionC (dll) in Include (tls.h) I have:
extern __declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage;
in the same soltuion but in Src i have tls.cpp with:
__declspec(dllexport) boost::thread_specific_ptr<int> ThreadLocalStorage;
and this is ok, compile with any problems.
SolutionB(dll) in file.pp I have:
__declspec(dllimport) boost::thread_specific_ptr<int> ThreadLocalStorage;
Did you forget 'extern' here?
participants (2)
-
Andrey Semashev
-
Fu ji