Cross-platform function to get the current thread ID

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Cross-platform function to get the current thread ID

Post by Mistrel »

A similar function like the Win32 GetCurrentThread() would be ideal for syncronizing data structures which use the Thread ID returned by CreateThread and functions called from within the thread itself. I find this particular API function is indispensable when working with threads and would love to see PureBasic support something similar for cross-platform compatibility as well.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Cross-platform function to get the current thread ID

Post by Keya »

I too need this! It would be great if we could use, for example, PB's ThreadId() with a -1 parameter or something
but at the moment it seems ThreadId() can only be used with threads we create with CreateThread() ?
does anyone know if there's a way? my Linux and Mac books wont arrive for at least another week!
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Cross-platform function to get the current thread ID

Post by wilbert »

On OSX you can use

Code: Select all

Debug CocoaMessage(0, 0, "NSThread currentThread")
and it will report different values for different threads but as far as I can tell it doesn't match the value the PureBasic ThreadID procedure returns :?


Edit:
After a bit more trying, on OSX PureBasic seems to use the value corresponding to pthread_self_() for ThreadID.

Code: Select all

Debug pthread_self_()
[/i]
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

BUG in ThreadId() for Windows? (works fine in Linux and OSX)

Post by Keya »

thankyou very much again wilbert!!! Without your help the shackles would still be on. Hopefully my Mac and Linux books arrive soon lol

It turns out Linux also uses pthread_self() ... im slowly "getting" Mac and Linux heehee :) :)

And its working well ... again a possible candidate for "ThreadId(-1)" or some new #PB_ThreadId_Current constant or something :D

But it seems there's a bug or unexplained result for PB's ThreadId() in WINDOWS (tested in XP-32 and 10-64) ...
[EDIT] Its not a bug, its just returning the thread HANDLE not the ID. wilbert found out we can use GetThreadId_(ThreadId(hPBThread)) in later versions of Windows, or we can just call GetCurrentThreadId_() from within the thread[/EDIT]

Also I check in Ollydbg but PB's ThreadId() in Windows never calls GetCurrentThread_/GetCurrentThreadId_ ... its very small code that only calls RtlEnterCriticalSection, WaitForSingleObject, and RtlLeaveCriticalSection but im not sure what its doing.

Image
(Ignore the Handle= value in OSX+Linux, i just wanted to see if GetCurrentThread_() was what ThreadId() is returning in Windows - it isn't)

This test simply creates a worker thread and retrieves the current thread ID from inside the worker thread so it can be reported and compared to the output of ThreadId(hWorkerThread)

Code: Select all

EnableExplicit
Global TestThreadId.l, TestThreadHandle.l, sTitle.s

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_MacOS
    ImportC ""
      pthread_self.l()
    EndImport 
  CompilerCase #PB_OS_Linux
    ImportC ""
      pthread_self.l()
    EndImport 
CompilerEndSelect


Procedure.l GetCurrentThreadId()      ;just added the sTitle lines for testing
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows    
      sTitle = "Windows, OSVersion()=" + Str(OSVersion())
      ProcedureReturn GetCurrentThreadId_()
    CompilerCase #PB_OS_MacOS
      sTitle = "OSX, OSVersion()=" + Str(OSVersion())
      ProcedureReturn pthread_self_()
    CompilerCase #PB_OS_Linux
      sTitle = "Linux, OSVersion()=" + Str(OSVersion())
      ProcedureReturn pthread_self_()
  CompilerEndSelect  
EndProcedure


Procedure TestThread(*threadParam)
  TestThreadId = GetCurrentThreadId()
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows    
    TestThreadHandle = GetCurrentThread_()
  CompilerEndIf
  Delay(500)  ;to give the primary thread time to call ThreadId(workerthread)
EndProcedure



Define hThread.l, PBThreadId.l
hThread = CreateThread(@TestThread(),0)
Delay(100) ;probably not needed
PBThreadId = ThreadID(hThread)
WaitThread(hThread)


MessageRequester("THREADID - " + sTitle,"Primary: ThreadId=0x" + Hex(GetCurrentThreadId(), #PB_Long) + #CRLF$ + 
                            "Worker: API ThreadId_ =0x" + Hex(TestThreadId, #PB_Long) + "  Handle=0x" + Hex(TestThreadHandle, #PB_Long) + #CRLF$ + 
                            "Worker: PBs ThreadID()=0x" + Hex(PBThreadId, #PB_Long) )
Ill wait for feedback or possibly Fred might notice this post, before possibly making a Bug report thread

ps. am I weird for thinking that it's strange that Mac's Cocoa uses strings instead of numeric constants like WinAPI? and from a readability perspective i find #NSThread_currentThread just as easy to read as "NSThread currentThread" lol :)
Last edited by Keya on Tue Sep 01, 2015 12:34 pm, edited 3 times in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Cross-platform function to get the current thread ID

Post by wilbert »

It looks like on Windows you need to use the API function GetThreadId to get the same values. :shock:

Code: Select all

Import ""
  GetThreadId(hThread)
EndImport

myThread = CreateThread(@TestThread(),0)
ThreadId = GetThreadId(ThreadID(myThread))
I'm not sure what you mean exactly with your remark about strings on OSX.
NSThread currentThread is not a constant but a class function.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Cross-platform function to get the current thread ID

Post by Keya »

wilbert wrote:It looks like on Windows you need to use the API function GetThreadId
Good catch! Yes in Windows it's returning a Handle, not ID. I verified by checking both the Threads and Handles windows in Ollydbg.
But this is a different handle to GetCurrentThread_() which confused me initially.
GetThreadId doesnt exist on XP tho, but its not really an issue in this case because GetCurrentThreadId_() is available

So in conclusion ... ThreadId() in Windows returns the Thread Handle/hThread.
whereas in Linux and OSX it returns the Thread ID. Would be good to mention this in the helpfile, or change ThreadID to correctly return GetCurrentThreadId_, and add another PB function GetThreadHandle.
I'm not sure what you mean exactly with your remark about strings on OSX.
NSThread currentThread is not a constant but a class function.
For example: Debug CocoaMessage(0, 0, "NSThread currentThread")
Where "NSThread currentThread" is a string and not constant like #NSThread_currentThread
Or is this something along the lines of an OSX version of GetProcAddress(LoadLibrary("NSThread"), "currentThread") ? which would make perfect sense being strings
Last edited by Keya on Tue Sep 01, 2015 12:17 pm, edited 1 time in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Cross-platform function to get the current thread ID

Post by wilbert »

On the lowest level, OSX uses the C functions listed in the "Objective-C Runtime Reference" (you can Google it) to work with Cocoa objects.
One of the most used functions is objc_msgSend to send a message to an object or class.
When the first Cocoa based version of PureBasic was released (PB 5.00) those functions were the only way to communicate with Cocoa objects.
You need quite a bit of code this way to do even simple things and it is complicated to return structures like a point or rectangle this way with PureBasic.

After PB 5.00 was released, some of us users (like me) were experimenting with this.
Since interacting with the objects PB creates is pretty important to set some platform specific things I wanted an easier solution so I started working on a userlib.
It was named oMsg ; an Objective C based user library which internally uses the NSInvocation class to interact with Cocoa objects and did also some things like PB string conversion to NSString for you.
Because quite a few users don't like to use user libraries (afraid support will suddenly end) and it would have been better to have a standard solution, I asked Fred to add the command to PureBasic itself.
After some of his feedback, he eventually added the final version of the oMsg command to PureBasic 5.10 (which I'm still thankful for) renamed as CocoaMessage to fit the way other procedures are named.

If you will study the NSInvocation class, you will understand that CocoaMessage works more or less like an interpreter (maybe the strings make a bit more sense now).
As a result of this, CocoaMessage is very flexible in what you can do with it without using any ImportC statements.
It's not super fast but fast enough for most purposes. For a time critical thing which uses a lot of calls, you can still revert to the low level functions (when you would compile an Objective-C source with XCode, you would see it uses those low level functions).
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Cross-platform function to get the current thread ID

Post by Keya »

oh my gosh i had no idea! Thankyou for the clarification, that makes a lot of sense :)
and megabig THANKYOU to you for all your hard work with oMsg and thankyou to Fred for giving it a proper home within PB - it removes the shackles and opens up a heck of a lot of doors!!! :) :) :)
I've also got plenty to read now about OSX API/Objective C while i want for my books to arrive heehee :)
Post Reply