ON ERROR GOTO to display problem line

General FreeBASIC programming questions.
paul doe
Moderator
Posts: 1735
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: ON ERROR GOTO to display problem line

Post by paul doe »

No wonder you're getting deadlocks. You're creating the mutex for the thread inside the thread itself, where other threads can't access it to sync. Have a look at this working example, using your code template:

Code: Select all

#include once "vbcompat.bi"

type _
  ClockThreadContext
 
  as any ptr _
    mutex
  as boolean _
    isRunning
end type

declare sub DISPLAYTIME ( byval as ClockThreadContext ptr )
declare SUB INPUTSCREEN ()


'Dim Mutex As Any Ptr            'create Mutex as a pointer
'Mutex   = MutexCreate()               

var _
  context => type <ClockThreadContext>( _
    mutexCreate(), _
    true )

var _
  hThread = ThreadCreate( _
    cptr( sub( byval as any ptr ), @DisplayTime ), _
    @context )           
'=======================================================================
SUB INPUTSCREEN()
  static as integer count
  
'=======================================================================
  locate 3, 1
  ? "Getting input: " & count
  
  count +=> 1
END SUB

'=======================================================================
SUB DISPLAYTIME ( _
  byval c As ClockThreadContext ptr )
'=======================================================================

  Do while( c->isRunning )
    MutexLock ( c->mutex )
    locate 9,8: print Format(Now, "hh:mm:ss")
      'If Is_Running=0 Then Exit Sub
    MutexUnLock (c->mutex )   
    Sleep 100, 1
  Loop
END SUB

dim as boolean _
  done

locate , , 0

do while( not done )
  mutexLock( context.mutex )
    locate 1, 1
    ? "Display, update, whatever"
    
    inputScreen()
  mutexUnlock( context.mutex )
 
  if( len( inkey() ) ) then
    done => true
  end if
 
  sleep( 1, 1 )
loop

'BELOW AT END OF PROGRAM:
context.isRunning => false

ThreadWait hThread       
'WRITETOFILE
'END

mutexDestroy( context.mutex )
Now, try to unmutex the calls to locate and print from the main thread, and you'll see why other threads need to access their mutexes to keep 'critical' data in sync. Create the mutex before spawning the thread, and keep it accessible for other threads too (including the main process and the thread itself); hence the 'context' var I pass here).
Last edited by paul doe on Jan 29, 2020 10:10, edited 1 time in total.
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

o.k., great, I am glad the problem is recognizable and I appreciate that you spent some time on the code. However, what you have provided back to me is very complicated from my perspective; again I am by no means what one would regard as an experienced programmer. All my past programming was only at the QuickBasic level.

Is there not a simpler code change that would work? But your response gives great hope in that I have spent days trying to figure out the problem. As I note, sometimes the code will execute as intended, then I would move on to make more changes, only to find out that the code still froze. Then back down some revisions and start again to try and find the problem.
mark
paul doe
Moderator
Posts: 1735
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: ON ERROR GOTO to display problem line

Post by paul doe »

Geez:

Code: Select all

#include once "vbcompat.bi"

declare sub DISPLAYTIME ( byval as any ptr )
declare SUB INPUTSCREEN ()

dim shared as any ptr _
  mutex

mutex => mutexCreate()

dim shared as boolean _
  isRunning => true
  
var _
  hThread = ThreadCreate( @DisplayTime, 0 )           

'=======================================================================
SUB INPUTSCREEN()
  static as integer count
 
'=======================================================================
  locate 3, 1
  ? "Getting input: " & count
 
  count +=> 1
END SUB

'=======================================================================
SUB DISPLAYTIME ( byval whatever as any ptr )
'=======================================================================
  Do while( isRunning )
    MutexLock ( mutex )
      locate 9,8: print Format(Now, "hh:mm:ss")
    MutexUnLock ( mutex )   
    Sleep 100, 1
  Loop
END SUB

dim as boolean _
  done

do while( not done )
  mutexLock( mutex )
    locate 1, 1
    ? "Display, update, whatever"
   
    inputScreen()
  mutexUnlock( mutex )
 
  if( len( inkey() ) ) then
    done => true
  end if
 
  sleep( 1, 1 )
loop

isRunning => false

ThreadWait hThread
mutexDestroy( mutex )
There. Rock-bottom low if you prefer.

EDIT: Forgot to release the mutex at the end.
Last edited by paul doe on Jan 29, 2020 10:08, edited 2 times in total.
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

Thanks for scaling down - I didn't get blown away! Late for me now, I will implement your code as I understand it tomorrow and be back.
mark
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

For the beauty of the thing, don't forget to destroy the mutex at the end (only when the thread is finished):

Code: Select all

.....
.....

isRunning => false

ThreadWait hThread

MutexDestroy ( mutex )
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

@mark bower,

General remark on some of your previous codes:
  • Inside any [Mutexlock...Mutexunlok] block (or any [Screenlock...Screenunlock] block) of any thread (main thread and user threads), never place an ending instruction as 'If ... Then Exit ...' because the mutex remains locked (or the screen locked) and then, therefore, any other thread cannot be executed (or the screen remains frozen).
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

@paul

I have code questions: 1) Why the counting in the SUB INPUTSCREEN; this sub is visited only once to make the start time & equipment plot parameters, 2) I do not understand where the "dim as boolean" & followng DO Loop" are inserted into my code, 3) the declare for STARTTIME is "( byval as any ptr )", the sub is "( byval 'whatever' as any ptr )" - what should the "whatever" be for my code? (I get "argument count mismatch in DISPLAYTIME" with a trial run).

To help with answering above, the following tells more of my code structure flow and flavor:

Code: Select all

MENU - select equip & Chs to plot(for help this selects option Acquire_2ch)
INPUTSCREEN - inputs parameters plus start time, current time already displayed, this called DISPLAYTIME
CALCULATIONS
CARTESIAN
INITIATE HARDWARE
WAITTOSTART
Acquire_2ch - this sub selected from input on INPUTSCREEN
        DO
        GET_DATA2
        PLOT2
        DELAY_INTERVAL
        if elapsedtime >= DurationTime then exit DO
        LOOP
Locate 25,9:print "Done"
Locate 26,1:print "Press Any Key to Exit"
sleep
"thread stuff"
WRITETOFILE
END
Last edited by mark bower on Jan 29, 2020 17:31, edited 1 time in total.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

I think we will not be able to help you successfully if you do not provide us with your current full code.
(I am afraid that in the main thread, INPUTSCREEN uses the INPUT keyword that so must compete with output keywords in the time-display thread)
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

fxm - it's a bit ugly, but here it is:

Code: Select all

SUB INPUTSCREEN
'=======================================================================
'Dim hThread As Any Ptr                  				'PER FB HELP, REMOVED FROM THIS LOCATION
'hThread = ThreadCreate(@DisplayTime,0)  		'PER FB HELP, REMOVED FROM THIS LOCATION 

dim as string YN,a    
dim as integer LINENUM

'WINDOW (0, 0)-(xres, yres)
LINE (xres *.2, yres *.1)-(xres *.8, yres *.45), 2, B     				'figure out colors later

LOCATE 2, (col - 12)/2: PRINT "INPUT SCREEN"

j= (col - 60)/2

sleep 1																	'req'd else next ln does not execute properly
Locate 10,j+1: Input "1. BEGIN TIME, INCLUDE ANY LEADING 0s & COLON(eg 06:15):  ",BTs

Do
	Locate 12,1+j: Print "2.  Duration in Hrs (eg, .1 to 24) ";:COLOR 5: PRINT "<1.0>:":COLOR 15 
	LOCATE 12,(60+j+2): Input "", DT
	If DT = 0 THEN
		DT =1
		LOCATE 12,(60+J+2): ? "1.0"
	ElseIf	DT < .1 or DT>24 then
		Locate 12,1+j: Print "Duration in Hrs (.1 to 24)               "
		LOCATE 28, (col - 34)/2: PRINT "<ENTER> OR <SPACE BAR> TO CONTINUE"
			DO
			a = INKEY
			LOOP UNTIL a = CHR(13) OR a = CHR(32)
		LOCATE 28, (col-34)/2: PRINT SPACE(34)
		Locate 12,(60+j): Print SPACE(5)
	End If
Loop Until DT >= .1 and DT <= 24

Locate 14,1+j: Print "3. INTERVAL FOR DATA CAPTURE IN MIN(.1 to 5) ";:COLOR 5: PRINT "<1>:":COLOR 15
LOCATE 14,(60+j+2): INPUT "",INTERVAL

IF Interval = 0 THEN 
	Interval = 1
	Locate 14,(60+j): ? 1
End If
'Note: Interval is changed from min to sec in Cartesian

Locate 16,1+j: Print "4. MAX VOLTS(ie 10,1,.1) ";:COLOR 5: PRINT "<10>:"
locate 16,110:Color 15:Input "", maxY

If maxY=0 then 
	maxY = 10
	LOCATE 16,(60+j): ? 10
End If

Locate 18,1+j: Print "5. SAMPLES PER CHANNEL: ";:COLOR 5: PRINT "<5>":COLOR 15
Locate 18,110:Color 15:Input "",samples   

If samples = 0 then
	samples = 5
	Locate 18,(60+j): PRINT samples
End If

''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Locate 20,1+j: Print "6. VOLTS MULTIPLIER: ";:COLOR 5: PRINT "<1>":COLOR 15
Locate 20,110:Color 15:Input "",multiplier   

If multiplier = 0 then
	multiplier = 1
	Locate 20,(60+j): PRINT multiplier
End If
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''

DO
	LOCATE 27, (col -40)/2: PRINT SPACE(50);
	LOCATE 27, (col -30)/2: PRINT "ARE THESE INPUT O.K. Y/N"; : COLOR 5: PRINT " <Y>: ";
	COLOR 15: YN = INPUT(1)
	IF YN = "Y" OR YN = "y" OR YN = CHR(13) THEN EXIT DO
	LOCATE 27, (col-40)/2: INPUT "THE LINE NUMBER OF THE ITEM TO CHANGE:  ", LINENUM
		
	DO WHILE LINENUM < 1 OR LINENUM >5									'entry outside range, request a new number
		LOCATE 27, 22: PRINT SPACE(43);
		LOCATE 27, (col-40)/2: INPUT "  PLEASE ENTER A NUMBER FROM 1 TO 5:  ", LINENUM
	LOOP
	
	IF LINENUM > 0 AND LINENUM < 6 THEN LOCATE LINENUM*2 + 8, 60+j: PRINT SPACE(10)  'meets criteria 1 to 5 & clears for new number

	SELECT CASE LINENUM
		CASE 1: LOCATE 10, (60+j+2): LINE INPUT ; BTs
		CASE 2: LOCATE 12, (60+j+2): INPUT "", DT
		CASE 3: LOCATE 14, (60+j+2): INPUT "", Interval
		CASE 4: LOCATE 16, (60+j+1): INPUT "", maxY
		CASE 5: LOCATE 18, (60+j+1): INPUT "", samples
	END SELECT
LOOP

END SUB
Last edited by mark bower on Jan 29, 2020 17:50, edited 1 time in total.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

And, if possible, your SUB for the time-display thread ?
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

@fxm - here it is. When the program freezes, the current time also locks up.

'=======================================================================
'SUB DISPLAYTIME (param As Any Ptr)
'=======================================================================
Dim Shared Mutex As Any Ptr
Mutex = MutexCreate()

Do
locate 9,8: print Format(Now, "hh:mm:ss")
Sleep 100
MutexLock (Mutex)
If Is_Running=0 Then Exit Sub
MutexUnLock (Mutex)
Loop
END SUB
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

When the program is running, do you occasionally see the time displayed in a wrong location, or the user dialogue in a wrong place on the screen?

What is your graphics screen resolution:
screenres ... ?
mark bower
Posts: 395
Joined: Dec 28, 2005 6:12
Location: arcadia, CA USA

Re: ON ERROR GOTO to display problem line

Post by mark bower »

No, the display and placements remain as they should - the time updates properly as the plot progresses. Not to confuse, but it does, with DISPLAYTIME remmed as below(sort of a discovery), the code can run to completion, BUT, sometimes it does not. And this looks like no use of Mutex.

Code: Select all

SUB DISPLAYTIME (param As Any Ptr)
'=======================================================================

''Dim Shared Mutex As Any Ptr            
''Mutex   = MutexCreate()                

Do
    locate 9,8: print Format(Now, "hh:mm:ss") 
    Sleep 100
'      MutexLock (Mutex)
    If Is_Running=0 Then Exit Sub
'      MutexUnLock (Mutex)
Loop
END SUB
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

fxm wrote:What is your graphics screen resolution:
screenres ... ?
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: ON ERROR GOTO to display problem line

Post by fxm »

Because of using INPUT in the main thread, a mutex (for mutual exclusion) can not be used in the DISPLAYTIME SUB thread (and in the main thread).

Replace your DISPLAYTIME SUB with the following (supposing your screen character size is 8x8):

Code: Select all

'======================================================================================
SUB DISPLAYTIME (param As Any Ptr) ' without flickering, for graphic character size 8x8
'======================================================================================

  Dim img As Any Ptr = ImageCreate(8*8, 8)  ' using an image buffer to avoid flickering
                                            ' (screen locking cannot be used in this thread)
 
  Do
   
    Line img, (0, 0)-(8*8-1, 8-1), 0, BF              ' clearing the image buffer
    Draw String img, (0, 0), Format(Now, "hh:mm:ss")  ' drawing in the image buffer
    Put ((8-1)*8, (9-1)*8), img, Pset                 ' copying the image buffer to screen
     
    Sleep 100, 1
   
  LOOP Until Is_Running = 0
 
  ImageDestroy img  ' destroying the image buffer

END SUB
Observe if the program still hangs ?


[edit]
code updated from first posting
Last edited by fxm on Feb 02, 2020 17:24, edited 2 times in total.
Post Reply