Thanks everyone for the suggestions. I really can’t submit an example project because this is what I am doing (and this is quite long FYI):
- Connecting to video hardware using either a URLConnection or a TCPSocket depending on the model of the device.
- Sending commands to capture either a JPEG or Bitmap from the devices depending on the model
- Taking the received string data and converting it into a memory block (I’ve also had problems with doing too many string operations in preemptive threads). I then start the thread.
- In the thread I am Validating that the data in the memory block is valid and converting it into a picture.
- Calling the UserInterfaceUpdate of the thread. If I have a picture passed I then loop through a dictionary of all the UI canvases that are registered to receive image data. I then call an interface method to send the picture to the canvases and they then paint the data.
- I then call the method that starts the whole process over again.
I have about 16 devices I am doing this to simultaneously. I’m pulling about 500 Mb/s of data across my network doing this. This is all I am doing in the thread:
Private Sub HandleImageThreadRun(t as thread)
Dim p As Picture
PicDataSemaphore.Signal
If IsMaxColor Then
#Pragma BreakOnExceptions Off
Try
p = Picture.FromData(HTMLContent)
'p = JPEGStringToPictureMBS(mcontent)
Catch
End Try
#Pragma BreakOnExceptionsOn
Else
// Need to validate that this is proper Bitmap file. BMP data has a file size value that is 4 bytes at offset 2
// Read that from the memory block and compare it to the size of the memory block.
Dim psize As Integer = HTMLContent.Int32Value(2)
If HTMLContent.Size = psize Then
p = Picture.FromData(HTMLContent)
End If
End If
PicDataSemaphore.Release
If p <> Nil Then
Select Case VideoRotation
Case JAPDevice.Rotation.VerticalMirror
p = p.VMirrorMBS
Case JAPDevice.Rotation.HorizontalMirror
p = p.HMirrorMBS
Case JAPDevice.Rotation.Rotate180Degrees
p = p.RotateMBS(180)
Case JAPDevice.Rotation.Rotate90DegreesClockwise
p = p.RotateMBS(90)
Case JAPDevice.Rotation.Rotate90DegreesClockwiseAndHorizontalMirror
p = p.RotateMBS(90)
p = p.HMirrorMBS
Case JAPDevice.Rotation.Rotate270DegreesClockwise
p = p.RotateMBS(270)
Case JAPDevice.Rotation.Rotate270DegreesClockwiseAndHorizontalMirror
p = p.RotateMBS(270)
p = p.HMirrorMBS
End Select
// Going to assume the image needs to be 16:9 Aspect ratio
// Correct it if not
If p.height/p.width <> 16/9 Then
Dim ppHeight As Integer = p.Height
Dim ppWidth As Integer = p.width
If p.Height > p.width Then
ppWidth = ppHeight*(16/9)
Else
ppHeight = ppWidth*(9/16)
End If
Dim pp1 As New Picture(ppWidth,ppHeight)
pp1.Graphics.DrawPicture(p,0,0,ppWidth,ppHeight,0,0,p.Width,p.Height)
p = pp1
End If
// Call the InterfaceUpdate so the main thread can send the image data to UI Controls
ImageThread.AddUserInterfaceUpdate("pic":p)
Else
// No picture - Raise the InterfaceUpdate but send nothing
// Then we can restart the process
Try
ImageThread.AddUserInterfaceUpdate(Nil:Nil)
Catch
End Try
End If
End Sub
There’s nothing there that is tied remotely to anything used by the UI. I left in one of the commented out commands I had been using from MonkeyBread. I was using string data but seeing random crashes. Not sure if Christian’s method is preemptive thread safe or not. But since I started using MemoryBlocks, I’m not having any issues on that side of things.
Now in the ContentReceived event of the URLConnection I have the following code:
Public Sub MaxColorURLConnectionContentReceived(u as urlconnection, URL as string, HTTPStatus as Integer, content as String)
PicDataSemaphore.Signal
HTMLContent = New MemoryBlock(content.Length)
HTMLContent.StringValue(0,content.Length)=content
PicDataSemaphore.Release
Dim i As Integer = 0
While ImageThread.ThreadState <> Thread.ThreadStates.NotRunning
If i < 100 Then
Thread.SleepCurrent(2)
Else
ImageThread.stop
Exit While
End If
i=i+1
Wend
If Not DontStartImageThread Then
ImageThread.Start
End If
End Sub
I won’t paste the TCPSocket DataAvailable code as it’s basically the same thing. The only objects that are being accessed by both the main thread and the preemptive thread are the memory block HTMLContent and the resulting picture. And both are protected by semaphores in each place.
Now, @Greg_O you said I should save the stack to a file when the exception happens. Been doing that for years! Here you go:
ThreadAccessingUIException
RuntimeRaiseException
REALbasic._UITrap
ListColumn.__Exit%%o
RuntimeUnlockObject
RuntimeLockUnlockObjects
JAPDevice.HandleImageThreadRun%%oo
Delegate.IM_Invoke%%o
threadRun
ZN4xojo11SpawnThreadEmPFvPvES0
_pthread_start
2024 4.8.0.782
Exact same stack every time.
Now I don’t know what ListColumn._Exit is. I am assuming that’s a Framework method.
Now here is some information I pulled from some of the crash reports.
First Report
Here is the thread that crashed:
Thread 18 Crashed:
0 libsystem_kernel.dylib 0x1981f2a60 __pthread_kill + 8
1 libsystem_pthread.dylib 0x19822ac20 pthread_kill + 288
2 libsystem_c.dylib 0x198137a30 abort + 180
3 libsystem_malloc.dylib 0x198047dc4 malloc_vreport + 896
4 libsystem_malloc.dylib 0x19804b430 malloc_report + 64
5 libsystem_malloc.dylib 0x198065494 find_zone_and_free + 528
6 XojoFramework 0x1037c44c4 0x103554000 + 2557124
7 XojoFramework 0x1037c4628 RuntimeLockUnlockObjects + 108
8 MediaSwitcher 0x101a5cbb8 JAPDevice.HandleImageThreadRun%%o<JAPDevice>o<Thread> + 5040
9 MediaSwitcher 0x100d79560 Delegate.IM_Invoke%%o<Thread> + 60
10 XojoFramework 0x1037d12fc 0x103554000 + 2609916
11 XojoFramework 0x103693c90 0x103554000 + 1309840
12 libsystem_pthread.dylib 0x19822af94 _pthread_start + 136
13 libsystem_pthread.dylib 0x198225d34 thread_start + 8
And here’s what was going on in the main thread:
Thread 0:: Dispatch queue: com.apple.main-thread
0 XojoFramework 0x1037d2298 0x103554000 + 2613912
1 XojoFramework 0x1037cfac8 0x103554000 + 2603720
2 XojoFramework 0x1036c731c RuntimeBackgroundTask + 68
3 MediaSwitcher 0x1015fb45c DeviceMaintWindow.DeviceMaintWindow.ScrollBarHorizontalVisible.Get%b%o<DeviceMaintWindow.DeviceMaintWindow>i4 + 720
4 MediaSwitcher 0x1015adf64 DeviceMaintWindow.DeviceMaintWindow.DeviceList_CellTextPaint%%o<DeviceMaintWindow.DeviceMaintWindow>o<ListBoxPopup>o<Graphics>i8i8i8i8 + 4532
5 MediaSwitcher 0x100e0d6b0 Delegate.IM_Invoke%%o<ListBoxPopup>o<Graphics>i8i8i8i8 + 100
6 MediaSwitcher 0x100e0d74c AddHandler.Stub.51%%o<Graphics>i8i8i8i8 + 136
7 MediaSwitcher 0x100eb0ea4 ListBoxPopup.Event_cellTextPaint%b%o<ListBoxPopup>o<Graphics>i8i8i8i8 + 1588
8 MediaSwitcher 0x100e463b4 AlternatingList.Event_CellTextPaint%b%o<AlternatingList>o<Graphics>i8i8i8i8 + 200
9 XojoFramework 0x10376315c RuntimeListbox::DrawCellText(Graphics*, xojo::Rect<xojo::Points> const*, CellEntry*, int, int, bool, bool, int) + 560
10 XojoFramework 0x103761fb0 RuntimeListbox::DrawCell(Graphics*, xojo::Rect<xojo::Points> const*, RowEntry*, CellEntry*, int, int, unsigned char) + 1016
11 XojoFramework 0x1037619f0 RuntimeListbox::HandleDrawRow(Graphics*, int, xojo::Rect<xojo::Points> const&, unsigned char, std::__1::vector<xojo::Rect<xojo::Points>, std::__1::allocator<xojo::Rect<xojo::Points>>> const&) + 524
12 XojoFramework 0x103760ec0 RuntimeListbox::RedrawCore(Graphics*, std::__1::vector<xojo::Rect<xojo::Points>, std::__1::allocator<xojo::Rect<xojo::Points>>> const&) + 536
13 XojoFramework 0x1037611d0 RuntimeListbox::Redraw(Graphics*, std::__1::vector<xojo::Rect<xojo::Points>, std::__1::allocator<xojo::Rect<xojo::Points>>> const&) + 220
14 XojoFramework 0x10364f4e0 0x103554000 + 1029344
15 AppKit 0x19bc817d4 _NSViewDrawRect + 124
16 AppKit 0x19c612cf0 -[NSView _recursive:displayRectIgnoringOpacity:inContext:stopAtLayerBackedViews:] + 1088
17 AppKit 0x19c612e88 -[NSView _recursive:displayRectIgnoringOpacity:inContext:stopAtLayerBackedViews:] + 1496
18 AppKit 0x19bc811d8 -[NSView(NSLayerKitGlue) _drawViewBackingLayer:inContext:drawingHandler:] + 556
19 AppKit 0x19c1b5f80 -[NSViewBackingLayer drawInContext:] + 56
Second Report
Here’s the second report thread that crashed and this looks to be all MacOS framework…
Thread 10 Crashed:: Dispatch queue: com.apple.CFNetwork.Connection
0 libsystem_kernel.dylib 0x1981f2a60 __pthread_kill + 8
1 libsystem_pthread.dylib 0x19822ac20 pthread_kill + 288
2 libsystem_c.dylib 0x198137a30 abort + 180
3 libsystem_malloc.dylib 0x198047dc4 malloc_vreport + 896
4 libsystem_malloc.dylib 0x19804b430 malloc_report + 64
5 libsystem_malloc.dylib 0x198065494 find_zone_and_free + 528
6 Network 0x19f6907a4 -[NWConcrete_nw_parameters dealloc] + 36
7 libobjc.A.dylib 0x197e5fe3c object_cxxDestructFromClass(objc_object*, objc_class*) + 116
8 libobjc.A.dylib 0x197e57688 objc_destructInstance + 80
9 libobjc.A.dylib 0x197e57634 _objc_rootDealloc + 80
10 Network 0x19fb70a8c -[NWConcrete_nw_path dealloc] + 100
11 Network 0x19fd26ea4 nw_association_update_paths + 284
12 Network 0x19fb81b34 nw_path_necp_update_evaluator + 1512
13 Network 0x19fb7faa8 nw_path_necp_check_for_updates + 3832
14 Network 0x19fba1adc nw_path_evaluator_force_update + 104
15 Network 0x19fd2d2b0 nw_association_force_update + 100
16 Network 0x19fc8b664 nw_endpoint_flow_setup_channel(NWConcrete_nw_endpoint_handler*) + 2212
17 Network 0x19fcaa0b0 -[NWConcrete_nw_endpoint_flow startWithHandler:] + 3664
18 Network 0x19f7cde30 nw_endpoint_handler_path_change(NWConcrete_nw_endpoint_handler*) + 7280
19 Network 0x19f7d73ec nw_endpoint_handler_start + 1624
20 Network 0x19f729c64 __nw_connection_start_block_invoke + 980
21 Network 0x19f729630 nw_connection_start + 508
22 CFNetwork 0x19d692ac4 0x19d545000 + 1366724
23 CFNetwork 0x19d68acc4 0x19d545000 + 1334468
24 CFNetwork 0x19d68bc54 0x19d545000 + 1338452
25 CFNetwork 0x19d6dae74 0x19d545000 + 1662580
26 CFNetwork 0x19d68a898 0x19d545000 + 1333400
27 CFNetwork 0x19d56b7dc 0x19d545000 + 157660
28 CFNetwork 0x19d6da348 0x19d545000 + 1659720
29 CFNetwork 0x19d6da4e4 0x19d545000 + 1660132
30 libdispatch.dylib 0x198078750 _dispatch_call_block_and_release + 32
31 libdispatch.dylib 0x19807a3e8 _dispatch_client_callout + 20
32 libdispatch.dylib 0x198081a14 _dispatch_lane_serial_drain + 748
33 libdispatch.dylib 0x198082578 _dispatch_lane_invoke + 432
34 libdispatch.dylib 0x198083898 _dispatch_workloop_invoke + 1756
35 libdispatch.dylib 0x19808d2d0 _dispatch_root_queue_drain_deferred_wlh + 288
36 libdispatch.dylib 0x19808cb44 _dispatch_workloop_worker_thread + 404
37 libsystem_pthread.dylib 0x19822700c _pthread_wqthread + 288
38 libsystem_pthread.dylib 0x198225d28 start_wqthread + 8
There’s not much in the main thread on this one unfortunately…This is just the Xojo related part where the exception is thrown
37 XojoFramework 0x1078c6b40 0x1077e0000 + 944960
38 XojoFramework 0x1078c6bc8 0x1077e0000 + 945096
39 MediaSwitcher 0x1045caae8 Application._CallFunctionWithExceptionHandling%%o<Application>p + 164
40 XojoFramework 0x107a4d930 CallFunctionWithExceptionHandling(void (*)()) + 180
41 XojoFramework 0x1078c6b64 0x1077e0000 + 944996
42 AppKit 0x19bb5b09c -[NSApplication run] + 476
43 XojoFramework 0x107a4c0b0 RuntimeRun + 60
44 MediaSwitcher 0x10475da74 REALbasic._RuntimeRun + 28
45 MediaSwitcher 0x105d49908 _Main + 476
46 MediaSwitcher 0x105d4643c main + 36
47 dyld 0x197ea20e0 start + 2360
Now what’s odd is that both of these crashes happened on my Mac Mini running a compiled version of my app. I left the app running last night on my laptop in the debugger and it’s still running solid since 5PM yesterday. Hasn’t crashed and I haven’t been able to make it crash…
Here’s the code that is in the CellTextPaint event of the listbox. The “JAPDevice” (JAP = Just Add Power - the name of the company who makes the devices I work with) is the object in code representing the physical hardware. This is the object running the threads in question.
Sub CellTextPaint(g as graphics, row as integer, column as integer, x as integer, y as integer) Handles CellTextPaint
Dim ln As Integer
DIm ErrorItem as string
If row < 0 or column < 0 Then
Return
End If
Dim j as JAPDevice
ln = 12
If me.RowTag(row) <> Nil AND me.RowTag(row) IsA JAPDevice Then
j = JAPDevice(me.RowTag(row))
End If
ln =16
Dim mwidths as String = me.ColumnWidths
Dim widths() As String = mwidths.Split(",")
If me.CellItalic(row,column) And column <> 0 Then
g.ForeColor = &c008040
End If
ln = 24
Select Case Column
Case 0
If me.RowIsFolder(row) Then
g.TextSize = 12
g.Bold = True
g.Underline = True
g.Italic = True
End If
ln = 36
Case 2
ln = 40
If j <> Nil Then
Dim colwidth as integer = val(widths(2))
ln=44
If Not ScrollBarHorizontalVisible Then
colwidth = ((colwidth/100)*Me.Width)
End If
Dim usethis As Integer = If(colwidth < Me.RowHeight, colwidth, Me.RowHeight)
Dim mx as integer = Abs((colwidth-usethis)/2)
ln = 51
Dim p as Picture
If j.Connected Then
p = GreenDot
If p = Nil Then
ErrorItem = "GreenDot + P Nil"
Else
ErrorItem = "GreenDot"
End If
Elseif j.AttemptingLogin Then
p = BallYellow
If p = Nil Then
ErrorItem = "BallYellow + P Nil"
Else
ErrorItem = "Ball Yellow"
End IF
Else
p = RedDot
If p = Nil Then
ErrorItem = "RedDot + P Nil"
Else
ErrorItem = "BallRed"
End If
ln = 63
Me.cell(row,6) = ""
Me.Cell(row,7) = ""
Me.Cell(row,8) = ""
Me.cell(row,8) = ""
If j.Rebooting Then
Me.Cell(row,10) = "Rebooting"
Else
Me.Cell(row,10) = ""
End If
Dim mSerialModes As MyPopup
ln=77
If DeviceList.CellTag(row,11) <> NIl Then
mSerialModes = MyPopUp(DeviceList.CellTag(row,11))
End If
ln=86
If mSerialModes <> Nil Then
mSerialModes.ListIndex = -1
End If
me.Cell(row,11) = ""
End If
ln=93
If p = nil Then ErrorItem = ErrorItem+ " P is Nil"
if g = nil Then ErrorItem = ErrorItem+ " G is Nil"
g.DrawPicture(p,mx,0,usethis,usethis,0,0,p.Width,p.Height)
End If
Case 4
If me.ScrollBarHorizontal Then
Dim zzz as INteger = 0
End If
ln=104
Dim colwidth As Integer = Val(widths(4))
If Not ScrollBarHorizontalVisible Then
colwidth = ((colwidth/100)*Me.Width)
End If
Dim usethis As Integer = If (colwidth < Me.RowHeight, colwidth, Me.RowHeight)
Dim mx As Integer = Abs((colwidth-usethis)/2)
ln=110
Dim p As Picture
If j = Nil OR Not j.Connected Then
Me.cell(row,column) = ""
Return
End If
ln=118
If j <> Nil And j.StatusDictionary <> Nil Then
Dim srvon As Boolean = j.StatusDictionary.Lookup("srv_on",false)
ln=122
If srvon Then
p= CheckboxFull
Else
p = CheckboxEmpty
End If
Else
p = CheckboxEmpty
End If
ln=132
g.DrawPicture(p,mx,0,usethis,usethis,0,0,p.Width,p.Height)
Case 5
ln=137
Dim colwidth As Integer = Val(widths(4))
If Not ScrollBarHorizontalVisible Then
colwidth = ((colwidth/100)*Me.Width)
End If
ln=143
Dim usethis As Integer = If (colwidth < Me.RowHeight, colwidth, Me.RowHeight)
Dim mx As Integer = Abs((colwidth-usethis)/2)
If j= Nil or Not j.Connected Or j.TX Then
Me.cell(row,column) = ""
Return
End If
ln=151
Dim p As Picture
If j <> Nil and j.StatusDictionary <> Nil Then
ln=156
Dim Attached As Boolean = j.StatusDictionary.Lookup("attached",False)
ln=157
If Attached Then
p= CheckboxFull
Else
p = CheckboxEmpty
End If
Else
p = CheckboxEmpty
End If
ln=167
g.DrawPicture(p,mx,0,usethis,usethis,0,0,p.Width,p.Height)
Case 8
ln=172
If j = Nil or Not j.Connected Then
Me.Cell(row,8) = ""
Return
End If
If j.StatusDictionary <> Nil Then
ln=180
If j.StatusDictionary.HasKey("StartDate_TimeUp") Then
ln=182
Dim StartDate as DateTime = j.StatusDictionary.Value("StartDate_TimeUp")
Dim UpTime As DateInterval = DateTime.Now-StartDate
Dim UpStr as string = str(UpTime.Days)+"d "+str(UpTime.Hours)+"h "+str(UpTime.Minutes)+"m "+str(UpTime.Seconds)+"s"
Me.Cell(row,8) = UpStr
ln=187
End If
End If
End Select
ln=201
Exception e as RuntimeException
Static MyLn as Integer = -1
Static MyRow as Integer = -1
Static MyCol as Integer = -1
Dim t As Xojo.Introspection.TypeInfo = Xojo.Introspection.GetType(e)
Dim eName as String
If t <> Nil Then
eName = t.FullName
End If
If MyLn <> ln And MyRow <> row and MyCol <> column Then
MyLn = Ln
MyRow = Row
MyCol = column
SendErrorEmail("Exception of Type "+ename+" has occured near Line Number "+Str(ln))
End If
End Sub
Yes I am touching the device that is running the thread. I’m accessing properties of the code object. The code object is pulling other data from the device over different TCPSockets or URLConnections, etc. But nothing is messing with the thread. Maybe there’s just a lot going on and I should semaphore the entire code object and not do any operations while the thread is running?
This is what the listbox looks like:
And what the whole screen running everything looks like: