ThreadID not working as expected?

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

ThreadID not working as expected?

Post by dougmo52usr »

I call GetCurrentThreadId on entry to my Thread function and save result to Global ThreadIdOS.
I also call CreateThread and save result to Global ThreadIdPB.
It seems that:
1. ThreadID(ThreadIdPB) <> ThreadIdOS
2. PostThreadMessage_(ThreadID(ThreadIdPB),#WM_USER,0,0) Fails
3. PostThreadMessage_(ThreadIdOS,#WM_USER,0,0) works
4. When using method 3, Debug shows:
TestThread entered
TestThread got Msg = 1024
TestThread got Msg = 1024
TestThread got Msg = 1024

I'm using version PureBasic 5.42 LTS (Windows - x86)

Here's the code just in case I'm doing something wrong:

Code: Select all

Global ThreadIdOS
Global ThreadIdPB
Declare TestThread(*ThreadIdOS)
In WinMain() before message loop:

Code: Select all

  ThreadIdPB = CreateThread(@TestThread(),@ThreadIdOS)
  SetTimer_(WindowID(Window_0),1,2000,0)
In WindowProc:

Code: Select all

Select Message
    Case #WM_TIMER
      If ThreadID(ThreadIdPB) = ThreadIdOS
        PostThreadMessage_(ThreadID(ThreadIdPB),#WM_USER,0,0)
      ElseIf IsThread(ThreadIdPB)      
        PostThreadMessage_(ThreadIdOS,#WM_USER,0,0)
      EndIf      
      ProcedureReturn 0
The thread function:

Code: Select all

;---------------------------
Procedure TestThread(*lpThreadId)
  Debug "TestThread entered"
  PokeL(*ThreadIdOS,GetCurrentThreadId_())
  Repeat
    Protected Msg.MSG
    If PeekMessage_(@Msg,0,#WM_USER,#WM_USER+16,#PM_NOREMOVE)
      If GetMessage_(@Msg,0,#WM_USER,#WM_USER+16)
        Debug "TestThread got Msg = " + Msg\message
      EndIf
    Else
      Sleep_(0)
    EndIf
  ForEver  
  Debug "TestThread exited"
EndProcedure
__________________________________________________
Code tags added
17.01.2017
RSBasic
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: ThreadID not working as expected?

Post by infratec »

Hi,

I can not test something, becaus it's nearly 12pm and you did not provide a working code to test.

Bernd
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: ThreadID not working as expected?

Post by infratec »

Hi,

a small working example:

Code: Select all

Procedure TestThread(*Dummy)
  Debug "GetCurrentThreadId: " + Str(GetCurrentThreadId_())
  Repeat
    Delay(10)
  ForEver
EndProcedure


Define.i Thread


OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

Thread = CreateThread(@TestThread(), #Null)

Debug "GetCurrentThreadId: " + Str(GetCurrentThreadId_())
Debug "Thread: " + Str(Thread)
Debug "ThreadID: " + Str(ThreadID(Thread))

Repeat
  
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_CloseWindow
      Exit = #True
  EndSelect
  
Until Exit
Result:
Image

Bernd
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

Re: ThreadID not working as expected?

Post by dougmo52usr »

Here is small app to show the issue. The value ThreadIdPB = CreateThread can not be passed to PostThreadMessage(ThreadId(ThreadIdPB) successfully, but the value ThreadIdOS = GetCurrentThreadId_() obtained within the thread function works in PostThreadMessage(ThreadIdOS.
I would expect ThreadIdOS would equal ThreadId(ThreadIdPB) since it is meant to be passed to the OS.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Code: Select all

Global Window_0

Global Button_0, Button_1

Declare OnBtnTestUsingThreadId(EventType)
Declare OnBtnTestUsingGetCurrentThreadId(EventType)

Procedure OpenWindow_0(x = 0, y = 0, width = 310, height = 100)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu)
  Button_0 = ButtonGadget(#PB_Any, 10, 10, 290, 25, "PostThreadMessage_(GetCurrentThreadId_(),...)")
  Button_1 = ButtonGadget(#PB_Any, 10, 50, 290, 30, "PostThreadMessage_(ThreadID(ThreadPB),'''')")
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
        Case Button_0
          OnBtnTestUsingGetCurrentThreadId(EventType())          
        Case Button_1
          OnBtnTestUsingThreadId(EventType())          
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

Global ThreadIdOS
Global ThreadIdPB

Declare TestThread(*ThreadIdOS)

Declare$ FormatMessage(ErrorNumber)

Declare WinMain()

WinMain()

Procedure WinMain()
  OpenWindow_0()
  ThreadIdPB = CreateThread(@TestThread(),@ThreadIdOS)
  SetTimer_(WindowID(Window_0),1,100,0)
  Repeat    
    Define Event = WaitWindowEvent()    
    Select EventWindow()
      Case Window_0        
        Window_0_Events(Event)         
    EndSelect 
  Until Event = #PB_Event_CloseWindow
EndProcedure

Procedure TestThread(*ThreadIdOS)
  Debug "TestThread entered"
  PokeL(*ThreadIdOS,GetCurrentThreadId_())
  Repeat
    Protected Msg.MSG
    If PeekMessage_(@Msg,0,#WM_USER,#WM_USER+16,#PM_NOREMOVE)
      If GetMessage_(@Msg,0,#WM_USER,#WM_USER+16)
        Debug "TestThread GetMessage #" + Hex(Msg\message,#PB_Word)
      EndIf
    Else
      Sleep_(0)
    EndIf
  ForEver  
  Debug "TestThread exited"
EndProcedure

Procedure OnBtnTestUsingGetCurrentThreadId(EventType)
  If Not PostThreadMessage_(ThreadIdOS,#WM_USER,0,0)
    Debug FormatMessage(GetLastError_())
  EndIf
EndProcedure

Procedure OnBtnTestUsingThreadId(EventType)
  If Not PostThreadMessage_(ThreadID(ThreadIdPB),#WM_USER,0,0)
    Debug FormatMessage(GetLastError_())
  EndIf
EndProcedure

Procedure$ FormatMessage(ErrorNumber)
  Protected sBuf.s = Space(#MAX_PATH)
  Protected lBuf.l = FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM,
                                    #Null,ErrorNumber,#Null,sBuf,Len(sBuf),#Null)
  If lBuf
    ProcedureReturn ReplaceString(sBuf,Chr(13)+Chr(10),"")
  Else
    ProcedureReturn "Errorcode: " + Hex(ErrorNumber)
  EndIf
EndProcedure
GJ-68
User
User
Posts: 32
Joined: Sun Jun 23, 2013 1:00 pm
Location: France (68)

Re: ThreadID not working as expected?

Post by GJ-68 »

As the name doesn't suggest, the PB function 'ThreadID(Thread)' returns the thread handle, not the thread ID.
From PureBasic help file:

Code: Select all

Return value:
The system identifier. This result is sometimes also known as 'Handle'. Look at the extra chapter Handles and Numbers for more information.
https://msdn.microsoft.com/en-us/librar ... 85%29.aspx

Code: Select all

Procedure TestThread(*Dummy)
	Debug "Thread ID: " + Str(GetCurrentThreadId_())
  Repeat
    Sleep_(100)
  ForEver
EndProcedure

Define.i Thread

OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
Thread = CreateThread(@TestThread(), #Null)
Debug "Thread Handle: " + RSet(Hex(ThreadID(Thread), #PB_Long), 8, "0")

Repeat
	Event = WaitWindowEvent()
	Select Event
		Case #PB_Event_CloseWindow
			Exit = #True
	EndSelect
Until Exit
Image
dougmo52usr
User
User
Posts: 55
Joined: Mon Jul 18, 2016 6:43 pm

Re: ThreadID not working as expected?

Post by dougmo52usr »

I can see the confusion.

The win32 function CreateThread returns a handle but also returns the ThreadId via the parameter lpThreadId. Although win32 typically uses a handle for other thread functions, For some unexplained reason PostThreadMessage wants the value referenced by lpThreadId.

To add to the confusion, when the value obtained by PBs ThreadId() is passed to PostThreadMessage, GetLastError_() returns "invalid handle value" instead of "invalid identifier value".

I see on MSDN that there is a DWORD WINAPI GetThreadId( _In_ HANDLE Thread); function. My win32.hlp version is dated and doesn't list it, and MSDN says it is for Vista or newer.

I would suggest that if PBs CreateThread calls windows CreateThread under the hood, that it provide a GetThreadId to allow obtaining the value referenced by the lpThreadId argument to CreateFile.

Code: Select all


HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,	// pointer to thread security attributes  
    DWORD dwStackSize,	// initial thread stack size, in bytes 
    LPTHREAD_START_ROUTINE lpStartAddress,	// pointer to thread function 
    LPVOID lpParameter,	// argument for new thread 
    DWORD dwCreationFlags,	// creation flags 
    LPDWORD lpThreadId 	// pointer to returned thread identifier 
   );
Rinzwind
Enthusiast
Enthusiast
Posts: 638
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: ThreadID not working as expected?

Post by Rinzwind »

Ouch, hit me too...
Post Reply