Author Topic: Script BASIC Extension Module  (Read 21367 times)

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: Script BASIC Extension Module - Threaded IUP
« Reply #30 on: May 16, 2015, 11:37:22 PM »
I have started working on the Linux version of thread support for IUP (not thread safe by design) like Charles has successfully done on Windows 32 bit using the DLLC extension module. I don't see that code base working for Linux and the 64 bit requirement puts it out of reach.

Current SBT Download Attached

The DLLC Windows 32 bit extension module can be found in the current OxygenBasic build and maintained by Charles Pegge.







Thread #1 script
Code: ScriptBasic
  1. ' Thread #1 Script
  2.  
  3. INCLUDE "dllcinc.sb"
  4.  
  5. iup = dllfile("iup.dll")
  6.  
  7. IupOpen          = dllproc(iup,"IupOpen          cdecl i = (i argc, i argv)")
  8. IupCreate        = dllproc(iup,"IupCreate        cdecl i = (c *classname)")
  9. IupSetAttributes = dllproc(iup,"IupSetAttributes cdecl i = (i ih, c *attr_str)")
  10. IupAppend        = dllproc(iup,"IupAppend        cdecl i = (i ih, cdecl i new_child)")
  11. IupSetCallback   = dllproc(iup,"IupSetCallback   cdecl i = (i ih, c*cb_name, i funcaddr)")
  12. IupShow          = dllproc(iup,"IupShow          cdecl i = (i ih)")
  13. IupMainLoop      = dllproc(iup,"IupMainLoop      cdecl i = ()")
  14. IupClose         = dllproc(iup,"IupClose         cdecl     ()")
  15.  
  16. GLOBAL CONST IUP_DEFAULT = -2
  17.  
  18. FUNCTION Btn1_T1(ih, mbut, pstat)
  19.   PRINT "B1 - T1 ", CHR(mbut), " - ", pstat, "\n"
  20.   Btn1_clicked = IUP_DEFAULT
  21. END FUNCTION
  22.  
  23. FUNCTION Btn2_T1(ih)
  24.   dllprnt"B2 - T1\n"
  25.   Btn2_clicked = IUP_DEFAULT
  26. END FUNCTION
  27.  
  28. FUNCTION Btn3_T1(ih)
  29.   dllprnt"B3 - T1\n"
  30.   Btn3_clicked = IUP_DEFAULT
  31. END FUNCTION
  32.  
  33. FUNCTION main(pProg,idat)
  34.   dllcall(IupOpen, 0, 0)
  35.   win = dllcall(IupCreate, "dialog")
  36.   dllcall(IupSetAttributes, win, "TITLE=\"Thread #1\", SIZE=300x")
  37.   horzbox = dllcall(IupCreate, "hbox")
  38.   dllcall(IupSetAttributes, horzbox, "GAP=5")
  39.   btn1 = dllcall(IupCreate, "button")
  40.   dllcall(IupSetAttributes, btn1, "TITLE=Button1, EXPAND=HORIZONTAL")
  41.   btn2 = dllcall(IupCreate, "button")
  42.   dllcall(IupSetAttributes, btn2, "TITLE=Button2, EXPAND=HORIZONTAL")
  43.   btn3 = dllcall(IupCreate, "button")
  44.   dllcall(IupSetAttributes, btn3, "TITLE=Button3, EXPAND=HORIZONTAL")
  45.   dllcall(IupAppend, horzbox, btn1)
  46.   dllcall(IupAppend, horzbox, btn2)
  47.   dllcall(IupAppend, horzbox, btn3)
  48.   dllcall(IupAppend, win, horzbox)
  49.   dllcall(IupSetCallback, btn1, "BUTTON_CB", dllclbk(1, pProg, "MAIN::Btn1_T1", 3,IUP_DEFAULT,idat))
  50.   dllcall(IupSetCallback, btn2, "ACTION", dllclbk(2, pProg, "MAIN::Btn2_T1", 1,IUP_DEFAULT,idat))
  51.   dllcall(IupSetCallback, btn3, "ACTION", dllclbk(3, pProg, "MAIN::Btn3_T1", 1,IUP_DEFAULT,idat))
  52.   dllcall(IupShow, win)
  53.   Main=IupMainLoop
  54. END FUNCTION
  55.  

Thread #2 script
Code: ScriptBasic
  1. ' Thread #2 Script
  2.  
  3. INCLUDE "dllcinc.sb"
  4.  
  5. iup = dllfile("iup.dll")
  6.  
  7. IupOpen          = dllproc(iup,"IupOpen          cdecl i = (i argc, i argv)")
  8. IupCreate        = dllproc(iup,"IupCreate        cdecl i = (c *classname)")
  9. IupSetAttributes = dllproc(iup,"IupSetAttributes cdecl i = (i ih, c *attr_str)")
  10. IupAppend        = dllproc(iup,"IupAppend        cdecl i = (i ih, cdecl i new_child)")
  11. IupSetCallback   = dllproc(iup,"IupSetCallback   cdecl i = (i ih, c*cb_name, i funcaddr)")
  12. IupShow          = dllproc(iup,"IupShow          cdecl i = (i ih)")
  13. IupMainLoop      = dllproc(iup,"IupMainLoop      cdecl i = ()")
  14. IupClose         = dllproc(iup,"IupClose         cdecl     ()")
  15.  
  16. GLOBAL CONST IUP_DEFAULT = -2
  17.  
  18. FUNCTION Btn1_T2(ih)
  19.   dllprnt"B1 - T2\n"
  20.   Btn1_clicked = IUP_DEFAULT
  21. END FUNCTION
  22.  
  23. FUNCTION Btn2_T2(ih)
  24.   dllprnt"B2 - T2\n"
  25.   Btn2_clicked = IUP_DEFAULT
  26. END FUNCTION
  27.  
  28. FUNCTION Btn3_T2(ih)
  29.   dllprnt"B3 - T2\n"
  30.   Btn3_clicked = IUP_DEFAULT
  31. END FUNCTION
  32.  
  33. FUNCTION main(pProg,idat)
  34.   dllcall(IupOpen, 0, 0)
  35.   win = dllcall(IupCreate, "dialog")
  36.   dllcall(IupSetAttributes, win, "TITLE=\"Thread #2\", SIZE=300x")
  37.   horzbox = dllcall(IupCreate, "hbox")
  38.   dllcall(IupSetAttributes, horzbox, "GAP=5")
  39.   btn1 = dllcall(IupCreate, "button")
  40.   dllcall(IupSetAttributes, btn1, "TITLE=Button1, EXPAND=HORIZONTAL")
  41.   btn2 = dllcall(IupCreate, "button")
  42.   dllcall(IupSetAttributes, btn2, "TITLE=Button2, EXPAND=HORIZONTAL")
  43.   btn3 = dllcall(IupCreate, "button")
  44.   dllcall(IupSetAttributes, btn3, "TITLE=Button3, EXPAND=HORIZONTAL")
  45.   dllcall(IupAppend, horzbox, btn1)
  46.   dllcall(IupAppend, horzbox, btn2)
  47.   dllcall(IupAppend, horzbox, btn3)
  48.   dllcall(IupAppend, win, horzbox)
  49.   dllcall(IupSetCallback, btn1, "ACTION", dllclbk(4, pProg, "MAIN::Btn1_T2", 1,IUP_DEFAULT,idat))
  50.   dllcall(IupSetCallback, btn2, "ACTION", dllclbk(5, pProg, "MAIN::Btn2_T2", 1,IUP_DEFAULT,idat))
  51.   dllcall(IupSetCallback, btn3, "ACTION", dllclbk(6, pProg, "MAIN::Btn3_T2", 1,IUP_DEFAULT,idat))
  52.   dllcall(IupShow, win)
  53.   Main=IupMainLoop
  54. END FUNCTION
  55.  

Start script
Code: ScriptBasic
  1. ' Boot (Main / Launcher)
  2.  
  3. INCLUDE "dllcinc.sb"
  4. bdat=string(8192,chr(0))
  5. idat=dllsptr(bdat)
  6.  
  7. thrM1 = dlltran("T1.sb","main::main",1,idat)
  8. thrM2 = dlltran("T2.sb","main::main",2,idat)
  9.  
  10. LINE INPUT wait
  11.  
  12. dllclos thrM1,thrM2
  13. dllfile
  14.  

Quote from: IUP site
Multithread

User interface is usually not thread safe and IUP is not thread safe. The general recommendation when you want more than one thread is to build the application and the user interface in the main thread, and create secondary threads that communicates with the main thread to update the interface. The secondary threads should not directly update the interface.

I discovered on the IUP mailing list a thread about IUP threads.  :)

Quote from: IUP Mailing List
Note that in GTK this is really easy to achieve:  GLib is thread-safe,
and so you can simply call g_idle_add from your worker thread to
register an idle callback.  The idle callback will then be called from
the GTK main loop in the IUP thread (since IUP simply uses the GTK main
loop, all this should work seamlessly without any modification to IUP).

Quote from: Otfried
Antonio Scuri wrote:
>   The IUP 3 GTK driver implements the Idle callback using g_idle_add, but it
> has the same effect as in the Windows driver. The Motif driver also uses a
> native X-Windows idle system, but the effect is also the same. I did a few
> tests at the time I implement it.
>
>   The effect is that the CPU consuming is very high, I mean the idle is
> called all the time. Why? When the mouse moves it should be NOT an "idle"
> time, but in fact it is. Weird but it is true. Between each mouse move there
> is a few milliseconds that there is no event to be processed, and the idle
> callback is then called between the move.

Having an active idle callback is very time consuming, so you should not
try to have an idle callback to poll for completion for another thread.

However, using 'g_idle_add' to signal completion (or to signal anything)
from a worker thread to the main thread works differently - it is very
CPU-efficient, and is in fact the recommended and standard way of doing
this using GTK/GLib.   The way it works is this:  Your main thread is
running the user interface, and is always waiting inside a gtk_main_loop
unless it is currently updating the UI.    When the worker thread has to
signal something (for instance that it has finished the work),  it
registers a callback function using 'g_idle_add'.   This will cause the
main thread to wake up from the gtk_main_loop and to execute this
callback function - it can collect the data from the worker thread and
display it on the UI.  The callback function returns FALSE, and
therefore unregisters itself immediately - so it is only run one single
time. This is why this is very efficient.

As I said, I think this is how one is supposed to do this in GTK, and it
can be implemented elegantly without changing IUP at all.  So I think
extra methods for this should _not_ be added to IUP for the GTK case.
In any case, if you are using threading in your application, you have to
use platform-specific code for the threading.  IUP should concentrate on
remaining a UI-library, and not try to offer platform-independent
threading support (like some monster libraries like Qt do...)

However, it doesn't seem that something like this is possible in
Windows, and it would be nice if IUP had the necessary features that
make signaling from a worker thread possible in Windows.

>   Giving a quick look at Glib I found "Asynchronous Queues"
> (g_async_queue_*) that seems to be what we want. But I'm not sure.

Asynchronous queues can be used to safely send data from one thread to
another without worrying about locking (it does that automatically).
However, to use this, the receiving thread still needs to check whether
data has arrived in the queue, so you need a way to wake up the IUP
thread when data is ready in the queue.  Again, the point is that the
main thread is blocking inside a gtk_main_loop, and one needs a
mechanism to wake it up.

Cheers,
   Otfried


Quote
While using g_idle_add() in a C code is straight forward

Code: C
  1.     g_idle_add ((GSourceFunc) functionA, someData);
  2.  

where functionA is a function defined in that C program file scope and someData is a structure
« Last Edit: May 17, 2015, 11:50:43 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: Script BASIC Extension Module
« Reply #31 on: May 17, 2015, 04:01:22 PM »
After taking a second peek at Charles's DLLC code, it made me believe I could return a SB execution pointer and make API calls from the host to a SB thread. My first attempts didn't work until I realize I might have a timing issue with access to a value of the structure. My curiosity paid off. Obviously this needs some work but it did prove my theory.

tget.sb
Code: ScriptBasic
  1. IMPORT sbt.inc
  2.  
  3. sb = SB_ThreadStart("setvars.sb")
  4. PRINT SB_GetVar(sb,"main::a")
  5. LINE INPUT wait
  6.  

setvars.sb
Code: ScriptBasic
  1. a = 123
  2. b = 1.23
  3. c = "One,Two,Three"
  4. SLEEP(5)
  5. SB_ThreadEnd
  6.  

Output

jrs@laptop:~/sb/sb22/sbt$ scriba tget.sb
123
jrs@laptop:~/sb/sb22/sbt$


Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: Script BASIC Extension Module
« Reply #32 on: May 17, 2015, 05:32:11 PM »
I made some improvements with interfacing with threads of Script BASIC.

  • I'm using usleep() for finer granularity.
  • I changed the default behavior of threads and they now act more like the embedded API I started off with. Now that I have the keys to the thread execution object, I no longer terminate the SB program when ended and allow the host to do it. This allow me to use all the embedded
  • MT can be used as an inter-thread message system. For example a MT variable could be set when it finished its task and ended before trying to access variables or call functions from the host.

Code: ScriptBasic
  1. IMPORT sbt.inc
  2.  
  3. sb = SB_ThreadStart("tcall.sb",undef,"/etc/scriba/basic.conf")
  4. SB_SetInt sb, "main::a", 123
  5. SB_SetDbl sb, "main::b", 1.23
  6. SB_SetStr sb, "main::c", "One, Two, Three"
  7. funcrtn = SB_CallSubArgs(sb, "main::prtvars", _
  8.           SB_GetVar(sb, "main::a"), _
  9.           SB_GetVar(sb, "main::b"), _
  10.           SB_GetVar(sb, "main::c"))      
  11. PRINT funcrtn,"\n"
  12. SB_Destroy sb
  13.  

Code: ScriptBasic
  1. FUNCTION prtvars(a, b, c)    
  2.   PRINT a,"\n"              
  3.   PRINT FORMAT("%g\n", b)  
  4.   PRINT c,"\n"              
  5.   prtvars = "Function Return"
  6. END FUNCTION                
  7.                              
  8. a = 0                        
  9. b = 0                        
  10. c = ""                      
  11.  


jrs@laptop:~/sb/sb22/sbt$ scriba tcallmain.sb
123
1.23
One, Two, Three
Function Return
jrs@laptop:~/sb/sb22/sbt$

« Last Edit: May 17, 2015, 06:52:51 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: Script BASIC Extension Module
« Reply #33 on: May 17, 2015, 07:09:29 PM »
Here is an example of rerunning the script in a thread.

Code: ScriptBasic
  1. IMPORT sbt.inc
  2.  
  3. sb = SB_ThreadStart("tprint.sb")
  4. SB_Run(sb,"")
  5. SB_Destroy(sb)
  6.  

Code: ScriptBasic
  1. PRINT 123,"\n"
  2. PRINT FORMAT("%g\n",1.23)
  3. PRINT "One,Two,Three\n"
  4.  


jrs@laptop:~/sb/sb22/sbt$ scriba tpmain.sb
123
1.23
One,Two,Three
123
1.23
One,Two,Three
jrs@laptop:~/sb/sb22/sbt$
« Last Edit: May 17, 2015, 07:40:18 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBT - IUP Threaded
« Reply #34 on: May 18, 2015, 03:02:51 PM »
I have made some progress following Charles's DLLC path. I wrapped the IUP creation and show in a function and call it from the main SB (boot) script. Both threaded GUI windows show but quickly go gray indicating overflow of it's event loop not being drained. My next task to figure out.


Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: SBT - IUP Threaded
« Reply #35 on: May 23, 2015, 07:10:16 PM »
I have made some progress with IUP running in a threaded mode. I still need to add the g_idle_add() to add thread support at the Gtk level.

iup.bas (callback functions)
Code: ScriptBasic
  1. FUNCTION MainLoop
  2. LOCAL this_event, aname
  3.   LoopStep()
  4.   this_event = GetEvent()
  5.   IF this_event <> undef THEN
  6.     aname = GetActionName()
  7.     IF this_event = event{this_event}[0] THEN
  8.       ICALL(event{this_event}[1])
  9.     END IF
  10.   END IF
  11.   MainLoop = aname
  12. END FUNCTION
  13.  
  14. FUNCTION SetCallback(ih, aname, fname)
  15.   event{ih}[0] = ih
  16.   event{ih}[1] = fname
  17.   SetCallback = __SetCallback(ih, aname)
  18. END FUNCTION
  19.  

iupmain.sb
Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3.  
  4. SUB SB_Wait(mtvar)
  5.   WHILE mt::GetVariable(mtvar) <> "OK"
  6.     SB_msSleep(20)
  7.   WEND
  8. END SUB
  9.  
  10. sb1 = SB_ThreadStart("rqdemo1.sb",undef,"/etc/scriba/basic.conf")
  11. SB_Wait("sb1_loaded")
  12.  
  13. sb1_rtn = SB_CallSub(sb1, "main::main")
  14. SB_Wait("sb1_main")
  15.  
  16. sb2 = SB_ThreadStart("rqdemo2.sb",undef,"/etc/scriba/basic.conf")
  17. SB_Wait("sb2_loaded")
  18.  
  19. sb2_rtn = SB_CallSub(sb2, "main::main")
  20. SB_Wait("sb2_main")
  21.  
  22. threads = 2
  23. sb1_active = TRUE
  24. sb2_active = TRUE
  25.  
  26. WHILE threads
  27.   IF sb1_active THEN
  28.     sb1_event_class = SB_CallSubArgs(sb1, "iup::mainloop")
  29.     IF sb1_event_class = "CLOSE_CB" THEN
  30.       sb1_active = FALSE
  31.       threads -= 1
  32.     END IF
  33.   END IF
  34.   IF sb2_active THEN
  35.     sb2_event_class = SB_CallSubArgs(sb2, "iup::mainloop")
  36.     IF sb2_event_class = "CLOSE_CB" THEN
  37.       sb2_active = FALSE
  38.       threads -= 1
  39.     END IF
  40.   END IF
  41. WEND
  42.  
  43. SB_CallSub(sb2, "iup::exitloop")
  44. SB_CallSub(sb1, "iup::exitloop")
  45.  

rqdemo1.sb (rqdemo2.sb is identical other than references as being the second thread)
Code: ScriptBasic
  1. ' Script BASIC Rapid-Q form conversion
  2.  
  3. IMPORT mt.bas
  4. IMPORT iup.bas
  5.  
  6. ' CALLBACKS FUNCTIONS
  7.  
  8. SUB button_quit
  9.   PRINT "Thread 1 Quit Button Pressed\n"
  10. END SUB  
  11.  
  12. SUB win_exit
  13.   ' Good-Bye  
  14. END SUB
  15.  
  16. SUB main
  17.  
  18.   ' SBIUP-Q INIT
  19.  
  20.   Iup::Open()
  21.   Iup::SetGlobal("DEFAULTFONT", "Sans, 7.5")
  22.  
  23.   ' CREATE FORM
  24.  
  25.   Form = Iup::Create("dialog")
  26.          Iup::SetAttributes(Form, "RASTERSIZE=320x240, TITLE=\"Thread 1\"")
  27.  
  28.        Label1  = Iup::Create("label")
  29.                  Iup::SetAttributes(Label1, "TITLE=\"Customer\", RASTERSIZE=55x13, FLOATING=YES, POSITION=\"19,19\"")
  30.  
  31.        Edit1   = Iup::Create("text")
  32.                  Iup::SetAttributes(Edit1, "RASTERSIZE=121x21, FLOATING=YES, POSITION=\"72,16\"")
  33.  
  34.        Button1 = Iup::Create("button")
  35.                  Iup::SetAttributes(Button1, "TITLE=\"&Quit\", RASTERSIZE=75x25, FLOATING=YES, POSITION=\"107,164\"")
  36.  
  37.   vbx = Iup::Vbox(Label1, Edit1, Button1)
  38.   Iup::Append(Form, vbx)
  39.                  
  40.   ' SET CALLBACKS
  41.  
  42.   Iup::SetCallback(Form, "CLOSE_CB", ADDRESS(win_exit()))
  43.   Iup::SetCallback(Button1, "ACTION", ADDRESS(button_quit()))
  44.   Iup::Show(Form)
  45.   mt::SetVariable("sb1_main","OK")
  46. END SUB
  47. mt::SetVariable("sb1_loaded","OK")
  48.  
« Last Edit: May 23, 2015, 10:18:55 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
IUP Threaded - Linux 64 bit - SBT
« Reply #36 on: May 24, 2015, 07:18:57 PM »
Done!

I finally got this worked out and didn't have to inform Gtk or IUP that they're being threaded8)

I can click on either thread window's button as fast as I can and it responds with the being pressed message. The only minor issue I still have is the second thread window will open in max size and sometimes without a max/restore window button. At this point I'm happy.

iup.bas - callback handling functions
Code: ScriptBasic
  1. FUNCTION MainLoop
  2. LOCAL hex_event
  3.   LoopStep()
  4.   this_event = GetEvent()
  5.   hex_event = BB_HTA(this_event)
  6.   IF hex_event = event{hex_event}[0] THEN
  7.     IF event{hex_event}[2] = 1 THEN
  8.       SB_CallSub(main::sb1, event{hex_event}[1])
  9.     ELSEIF event{hex_event}[2] = 2 THEN
  10.       SB_CallSub(main::sb2, event{hex_event}[1])
  11.     END IF
  12.     MainLoop = GetActionName()
  13.   END IF  
  14. END FUNCTION
  15.  
  16. FUNCTION SetThreadCallback(ih, aname, fname, tnum)
  17.   t_event = mt::GetVariable("Callback_Map")
  18.   IF t_event = undef THEN t_event = ""
  19.   t_event = t_event & BB_HTA(ih) & "|" & fname & "|" & tnum & "\n"
  20.   mt::SetVariable("Callback_Map", t_event)
  21.   SetThreadCallback = __SetCallback(ih, aname)
  22. END FUNCTION
  23.  
  24. SUB GetThreadCallback
  25.   LOCAL t_event, e_list, e_array, x
  26.   t_event = mt::GetVariable("Callback_Map")
  27.   SPLITA t_event BY "\n" TO e_list
  28.   FOR x = 0 TO UBOUND(e_list)
  29.     SPLITA e_list[x] BY "|" TO e_array
  30.     event{e_array[0]}[0] = e_array[0]
  31.     event{e_array[0]}[1] = e_array[1]
  32.     event{e_array[0]}[2] = e_array[2]
  33.   NEXT
  34. END SUB
  35.  
  36. FUNCTION BB_HTA(AsciiStr)
  37.   LOCAL AsciiLen,ScanPos,HexStr
  38.   AsciiLen = LEN(AsciiStr)
  39.   HexStr = ""
  40.   IF AsciiLen THEN
  41.     FOR ScanPos = 1 TO AsciiLen
  42.       HexStr &= RIGHT("0" & HEX(ASC(MID(AsciiStr, ScanPos, 1))),2)
  43.     NEXT ScanPos
  44.   ELSE
  45.     HexStr = ""
  46.   END IF
  47.   BB_HTA = HexStr
  48. END FUNCTION
  49.  

iupmain.sb - host SB script (puppet master)
Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3. IMPORT iup.bas
  4.  
  5. Iup::Open()
  6.  
  7. SUB SB_Wait(mtvar)
  8.   WHILE mt::GetVariable(mtvar) <> "OK"
  9.     SB_msSleep(5000)
  10.   WEND
  11. END SUB
  12.  
  13. sb1 = SB_ThreadStart("rqdemo1.sb",undef,"/etc/scriba/basic.conf")
  14. SB_Wait("sb1_loaded")
  15. sb1_rtn = SB_CallSubArgs(sb1, "main::main", sb1)
  16.  
  17. sb2 = SB_ThreadStart("rqdemo2.sb",undef,"/etc/scriba/basic.conf")
  18. SB_Wait("sb2_loaded")
  19. sb2_rtn = SB_CallSubArgs(sb2, "main::main", sb2)
  20.  
  21. threads = 2
  22.  
  23. Iup::GetThreadCallback()
  24.  
  25. WHILE threads
  26.   event_class = Iup::MainLoop()
  27.   IF event_class = "CLOSE_CB" THEN
  28.     threads -= 1
  29.     IF Iup::event{Iup::BB_HTA(Iup::this_event)}[2] = 1 THEN
  30.       SB_CallSub(sb1, "iup::exitloop")
  31.     ELSEIF Iup::event{Iup::BB_HTA(Iup::this_event)}[2] = 2 THEN
  32.       SB_CallSub(sb2, "iup::exitloop")
  33.     END IF
  34.   END IF  
  35.   SB_msSleep(250)
  36. WEND
  37.  
  38. Iup::Close()
  39. SB_Destroy(sb2)
  40. SB_Destroy(sb1)
  41.  

rqdemo1.sb - rqdemo2.sb is identical other than the references to it been the second thread.
Code: ScriptBasic
  1. ' Script BASIC Rapid-Q form conversion
  2.  
  3. IMPORT mt.bas
  4. IMPORT iup.bas
  5.  
  6. DECLARE OPTION DeclareVars
  7. GLOBAL Form, Label1, Edit1, Button1, vbx, event
  8.  
  9. ' CALLBACKS FUNCTIONS
  10.  
  11. SUB button_quit
  12.   PRINT "Thread 1 Quit Button Pressed\n"
  13. END SUB  
  14.  
  15. SUB win_exit
  16.   ' Good-Bye  
  17. END SUB
  18.  
  19. SUB main
  20.  
  21.   ' SBIUP-Q INIT
  22.  
  23.   Iup::Open()
  24.   Iup::SetGlobal("DEFAULTFONT", "Sans, 7.5")
  25.  
  26.   ' CREATE FORM
  27.  
  28.   Form = Iup::Create("dialog")
  29.          Iup::SetAttributes(Form, "RASTERSIZE=320x240, TITLE=\"Thread 1\"")
  30.  
  31.        Label1  = Iup::Create("label")
  32.                  Iup::SetAttributes(Label1, "TITLE=\"Customer\", RASTERSIZE=55x13, FLOATING=YES, POSITION=\"19,19\"")
  33.  
  34.        Edit1   = Iup::Create("text")
  35.                  Iup::SetAttributes(Edit1, "RASTERSIZE=121x21, FLOATING=YES, POSITION=\"72,16\"")
  36.  
  37.        Button1 = Iup::Create("button")
  38.                  Iup::SetAttributes(Button1, "TITLE=\"&Quit\", RASTERSIZE=75x25, FLOATING=YES, POSITION=\"107,164\"")
  39.  
  40.   vbx = Iup::Vbox(Label1, Edit1, Button1)
  41.   Iup::Append(Form, vbx)
  42.                  
  43.   ' SET CALLBACKS
  44.  
  45.   Iup::SetThreadCallback(Form, "CLOSE_CB", "main::win_exit", 1)
  46.   Iup::SetThreadCallback(Button1, "ACTION", "main::button_quit", 1)
  47.   Iup::Show(Form)
  48. END SUB
  49. mt::SetVariable("sb1_loaded","OK")
  50.  
« Last Edit: May 25, 2015, 01:19:20 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBx Buttons - Threaded
« Reply #37 on: May 25, 2015, 02:54:22 PM »
Here is a threaded IUP example that uses the container position method rather than fixed pixel to emulate the Rapid-Q form. The other goal was to see if my extended events arguments were available. They work but cause additional T2 startup display issues. There is something strange going on with IUP in its dialog initialization that is random and caused the position system to return strange results. I get a max window or changed size from what was define. The stranger part is it only happens in the second thread.

SBx_Main
Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3. IMPORT iup.bas
  4.  
  5. Iup::Open()
  6.  
  7. SUB SB_Wait(mtvar)
  8.   WHILE mt::GetVariable(mtvar) <> "OK"
  9.     SB_msSleep(5000)
  10.   WEND
  11. END SUB
  12.  
  13. sb1 = SB_ThreadStart("SBx_T1",undef,"/etc/scriba/basic.conf")
  14. SB_Wait("sb1_loaded")
  15. sb1_rtn = SB_CallSubArgs(sb1, "main::main", sb1)
  16.  
  17. sb2 = SB_ThreadStart("SBx_T2",undef,"/etc/scriba/basic.conf")
  18. SB_Wait("sb2_loaded")
  19. sb2_rtn = SB_CallSubArgs(sb2, "main::main", sb2)
  20.  
  21. threads = 2
  22.  
  23. Iup::GetThreadCallback()
  24.  
  25. WHILE threads
  26.   event_class = Iup::MainLoop()
  27.   IF event_class = "CLOSE_CB" THEN
  28.     threads -= 1
  29.     IF Iup::event{Iup::BB_HTA(Iup::this_event)}[2] = 1 THEN
  30.       SB_CallSub(sb1, "iup::exitloop")
  31.     ELSEIF Iup::event{Iup::BB_HTA(Iup::this_event)}[2] = 2 THEN
  32.       SB_CallSub(sb2, "iup::exitloop")
  33.     END IF
  34.   END IF  
  35.   SB_msSleep(250)
  36. WEND
  37.  
  38. Iup::Close()
  39. SB_Destroy(sb2)
  40. SB_Destroy(sb1)
  41.  

SBx_T1 (SBX_T2 is basically the same)
Code: ScriptBasic
  1. ' SBx_buttons Example (Thread 1)
  2.  
  3. IMPORT mt.bas
  4. IMPORT iup.bas
  5. IMPORT "SBx"
  6.  
  7. SUB btn1_clicked
  8.   PRINT "Thread 1 Button 1 Pressed\n"
  9. ' PRINT "Button: ",CHR(Iup::GetBtnPressed()),"\n"
  10. ' PRINT "State: ",Iup::GetBtnState(),"\n"
  11. END SUB
  12.  
  13. SUB btn2_clicked
  14.   PRINT "Thread 1 Button 2 Pressed\n"
  15. END SUB
  16.  
  17. SUB btn3_clicked
  18.   PRINT "Thread 1 Button 3 Pressed\n"
  19. END SUB
  20.  
  21. SUB win_exit
  22.   ' Good-Bye
  23. END SUB
  24.  
  25. SUB main
  26.  
  27. Iup::Open()
  28.  
  29. win = DIALOG()
  30. SETPROPERTIES win, "TITLE=\"SBx Thread 1\", SIZE=300x"
  31. horzbox = HBOX()
  32. SETPROPERTIES horzbox, "GAP=5"
  33. btn1 = BUTTON()
  34. SETPROPERTIES btn1, "TITLE=\"Button 1\", EXPAND=HORIZONTAL"
  35. btn2 = BUTTON()
  36. SETPROPERTIES btn2, "TITLE=\"Button 2\", EXPAND=HORIZONTAL"
  37. btn3 = BUTTON()
  38. SETPROPERTIES btn3, "TITLE=\"Button 3\", EXPAND=HORIZONTAL"
  39. APPEND horzbox, btn1
  40. APPEND horzbox, btn2
  41. APPEND horzbox, btn3
  42. APPEND win, horzbox
  43. Iup::SetThreadCallback(win, "CLOSE_CB", "main::win_exit", 1)
  44. ' Iup::SetThreadCallback(btn1, "BUTTON_CB", "main::btn1_clicked", 1)
  45. Iup::SetThreadCallback(btn1, "ACTION", "main::btn1_clicked", 1)
  46. Iup::SetThreadCallback(btn2, "ACTION", "main::btn2_clicked", 1)
  47. Iup::SetThreadCallback(btn3, "ACTION", "main::btn3_clicked", 1)
  48. SHOW win
  49. END SUB
  50. mt::SetVariable("sb1_loaded","OK")
  51.  

SBx (experimental IUP wrapper)
Code: ScriptBasic
  1. ' ScriptBasic IUP Interface
  2.  
  3. FUNCTION DIALOG
  4.   DIALOG = Iup::Create("dialog")
  5. END FUNCTION
  6.  
  7. SUB SETPROPERTIES(ih, propstr)
  8.   Iup::SetAttributes(ih, propstr)
  9. END SUB
  10.  
  11. SUB SETPROPERTY(ih, typ, value)
  12.   Iup::SetAttribute(ih, typ, value)
  13. END SUB
  14.  
  15. FUNCTION GETPROPERTY(ih, typ)
  16.   GETPROPERTY = Iup::GetAttribute(ih, typ)
  17. END FUNCTION
  18.  
  19. FUNCTION VBOX
  20.   VBOX = Iup::Create("vbox")
  21. END FUNCTION
  22.  
  23. FUNCTION HBOX
  24.   HBOX = Iup::Create("hbox")
  25. END FUNCTION
  26.  
  27. FUNCTION FRAME
  28.   FRAME = Iup::Create("frame")
  29. END FUNCTION
  30.  
  31. FUNCTION BUTTON
  32.   BUTTON = Iup::Create("button")
  33. END FUNCTION
  34.  
  35. FUNCTION LIST
  36.   LIST = Iup::Create("list")
  37. END FUNCTION
  38.  
  39. FUNCTION TEXT
  40.   TEXT = Iup::Create("text")
  41. END FUNCTION
  42.  
  43. FUNCTION LABEL
  44.   LABEL = Iup::Create("label")
  45. END FUNCTION
  46.  
  47. FUNCTION TOGGLE
  48.   TOGGLE = Iup::Create("toggle")
  49. END FUNCTION
  50.  
  51. SUB MESSAGE(title, body)
  52.   Iup::Message(title, body)
  53. END SUB
  54.  
  55. FUNCTION GETITEM
  56.   GETITEM = Iup::GetListText()
  57. END FUNCTION
  58.  
  59. SUB APPEND(ih_to, ih_from)
  60.   Iup::Append(ih_to, ih_from)
  61. END SUB
  62.  
  63. FUNCTION FOCUS(ih)
  64.   FOCUS = Iup::SetFocus(ih)
  65. END FUNCTION
  66.  
  67. FUNCTION UPDATE(ih)
  68.   UPDATE = Iup::Update(ih)
  69. END FUNCTION
  70.  
  71. SUB CLEAR(ih)
  72.   Iup::ClearList(ih)
  73. END SUB
  74.  
  75. SUB SETEVENT(ih, class, funcaddr)
  76.   Iup::SetCallback(ih, class,  funcaddr)
  77. END SUB
  78.  
  79. SUB SHOW(ih)
  80.   Iup::Show(ih)
  81. END SUB  
  82.  
  83. SUB GETEVENT
  84.   Iup::MainLoop
  85.   Iup::Close
  86. END SUB
  87.  

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: SBx Buttons - Threaded - (Extended Status)
« Reply #38 on: May 25, 2015, 03:23:23 PM »
I disabled the Iup::Open() in the threads and the Iup::ExitLoop in SBx_Main seems to make the SBx Buttons demo startup more consistently in the defined size. I also show the extended event arguments in this screen shot.

FYI: This doesn't seem to help the fixed position IUP (Rapid-Q) example posted earlier.

Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3. IMPORT iup.bas
  4.  
  5. Iup::Open()
  6.  
  7. SUB SB_Wait(mtvar)
  8.   WHILE mt::GetVariable(mtvar) <> "OK"
  9.     SB_msSleep(5000)
  10.   WEND
  11. END SUB
  12.  
  13. sb1 = SB_ThreadStart("SBx_T1",undef,"/etc/scriba/basic.conf")
  14. SB_Wait("sb1_loaded")
  15. sb1_rtn = SB_CallSubArgs(sb1, "main::main", sb1)
  16.  
  17. sb2 = SB_ThreadStart("SBx_T2",undef,"/etc/scriba/basic.conf")
  18. SB_Wait("sb2_loaded")
  19. sb2_rtn = SB_CallSubArgs(sb2, "main::main", sb2)
  20.  
  21. threads = 2
  22.  
  23. Iup::GetThreadCallback()
  24.  
  25. WHILE threads
  26.   event_class = Iup::MainLoop()
  27.   IF event_class = "CLOSE_CB" THEN
  28.     threads -= 1
  29.   END IF  
  30.   SB_msSleep(250)
  31. WEND
  32.  
  33. Iup::Close()
  34. SB_Destroy(sb2)
  35. SB_Destroy(sb1)
  36.  

Code: ScriptBasic
  1. ' SBx_buttons Example (Thread 1)
  2.  
  3. IMPORT mt.bas
  4. IMPORT iup.bas
  5. IMPORT "SBx"
  6.  
  7. SUB btn1_clicked
  8.   PRINT "Thread 1 Button 1 Pressed\n"
  9.   PRINT "Which Mouse Button: ",CHR(Iup::GetBtnPressed()),"\n"
  10.   PRINT "Button Up/Dn State: ",Iup::GetBtnState(),"\n"
  11. END SUB
  12.  
  13. SUB btn2_clicked
  14.   PRINT "Thread 1 Button 2 Pressed\n"
  15. END SUB
  16.  
  17. SUB btn3_clicked
  18.   PRINT "Thread 1 Button 3 Pressed\n"
  19. END SUB
  20.  
  21. SUB win_exit
  22.   ' Good-Bye
  23. END SUB
  24.  
  25. SUB main
  26.  
  27. ' Iup::Open()
  28.  
  29. win = DIALOG()
  30. SETPROPERTIES win, "TITLE=\"SBx Thread 1\", SIZE=300x"
  31. horzbox = HBOX()
  32. SETPROPERTIES horzbox, "GAP=5"
  33. btn1 = BUTTON()
  34. SETPROPERTIES btn1, "TITLE=\"Button 1\", EXPAND=HORIZONTAL"
  35. btn2 = BUTTON()
  36. SETPROPERTIES btn2, "TITLE=\"Button 2\", EXPAND=HORIZONTAL"
  37. btn3 = BUTTON()
  38. SETPROPERTIES btn3, "TITLE=\"Button 3\", EXPAND=HORIZONTAL"
  39. APPEND horzbox, btn1
  40. APPEND horzbox, btn2
  41. APPEND horzbox, btn3
  42. APPEND win, horzbox
  43. Iup::SetThreadCallback(win, "CLOSE_CB", "main::win_exit", 1)
  44. Iup::SetThreadCallback(btn1, "BUTTON_CB", "main::btn1_clicked", 1)
  45. Iup::SetThreadCallback(btn2, "ACTION", "main::btn2_clicked", 1)
  46. Iup::SetThreadCallback(btn3, "ACTION", "main::btn3_clicked", 1)
  47. SHOW win
  48. END SUB
  49. mt::SetVariable("sb1_loaded","OK")
  50.  
« Last Edit: May 25, 2015, 04:30:57 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBT IUP Threaded SBx Buttons 3*3
« Reply #39 on: May 25, 2015, 06:46:53 PM »
The solution to my unstable IUP start-up issues were resolved with creating an IUP dialog in the parent script before creating threaded children dialogs.  I moved the Iup::MainLoop and Iup::GetThreadCallback routines into the main script from the IUP extension module. At this point everything is working as expected and I couldn't be happier.

Moral: How can you have well behaved children if you don't have a mature parent in charge?  ::)

SBx_Main
Code: ScriptBasic
  1. ' SBT IUP Theaded Example
  2.  
  3. IMPORT mt.bas
  4. IMPORT sbt.inc
  5. IMPORT iup.bas
  6. IMPORT "SBx"
  7.  
  8. Iup::Open()
  9.  
  10. SUB SB_Wait(mtvar)
  11.   WHILE mt::GetVariable(mtvar) <> "OK"
  12.     SB_msSleep(5000)
  13.   WEND
  14. END SUB
  15.  
  16. SUB btn1_clicked
  17.   PRINT "Main 0 Button 1 Pressed\n"
  18.   PRINT "Which Mouse Button: ",CHR(Iup::GetBtnPressed()),"\n"
  19.   PRINT "Button Up/Dn State: ",Iup::GetBtnState(),"\n"
  20. END SUB
  21.  
  22. SUB btn2_clicked
  23.   PRINT "Main 0 Button 2 Pressed\n"
  24. END SUB
  25.  
  26. SUB btn3_clicked
  27.   PRINT "Main 0 Button 3 Pressed\n"
  28. END SUB
  29.  
  30. SUB win_exit
  31.   ' Good-Bye
  32. END SUB
  33.  
  34. win = DIALOG()
  35. SETPROPERTIES win, "TITLE=\"SBx Main 0\", SIZE=300x"
  36. horzbox = HBOX()
  37. SETPROPERTIES horzbox, "GAP=5"
  38. btn1 = BUTTON()
  39. SETPROPERTIES btn1, "TITLE=\"Button 1\", EXPAND=HORIZONTAL"
  40. btn2 = BUTTON()
  41. SETPROPERTIES btn2, "TITLE=\"Button 2\", EXPAND=HORIZONTAL"
  42. btn3 = BUTTON()
  43. SETPROPERTIES btn3, "TITLE=\"Button 3\", EXPAND=HORIZONTAL"
  44. APPEND horzbox, btn1
  45. APPEND horzbox, btn2
  46. APPEND horzbox, btn3
  47. APPEND win, horzbox
  48. Iup::SetThreadCallback(win, "CLOSE_CB", ADDRESS(win_exit()), 0)
  49. Iup::SetThreadCallback(btn1, "BUTTON_CB", ADDRESS(btn1_clicked()), 0)
  50. Iup::SetThreadCallback(btn2, "ACTION", ADDRESS(btn2_clicked()), 0)
  51. Iup::SetThreadCallback(btn3, "ACTION", ADDRESS(btn3_clicked()), 0)
  52. SHOW win
  53.  
  54. ' Puppet Show
  55.  
  56. sb1 = SB_ThreadStart("SBx_T1",undef,"/etc/scriba/basic.conf")
  57. SB_Wait("sb1_loaded")
  58. sb1_rtn = SB_CallSubArgs(sb1, "main::main", sb1)
  59.  
  60. sb2 = SB_ThreadStart("SBx_T2",undef,"/etc/scriba/basic.conf")
  61. SB_Wait("sb2_loaded")
  62. sb2_rtn = SB_CallSubArgs(sb2, "main::main", sb2)
  63.  
  64. threads = 3
  65.  
  66. t_event = mt::GetVariable("Callback_Map")
  67. SPLITA t_event BY "\n" TO e_list
  68. FOR x = 0 TO UBOUND(e_list)
  69.   SPLITA e_list[x] BY "|" TO e_array
  70.   event{e_array[0]}[0] = e_array[0]
  71.   event{e_array[0]}[1] = e_array[1]
  72.   event{e_array[0]}[2] = e_array[2]
  73. NEXT
  74.  
  75. WHILE threads
  76.   Iup::LoopStep()
  77.   this_event = Iup::GetEvent()
  78.   hex_event = Iup::BB_HTA(this_event)
  79.   IF hex_event = event{hex_event}[0] THEN
  80.     IF event{hex_event}[2] = 0 THEN
  81.       ICALL event{hex_event}[1]
  82.     ELSE IF event{hex_event}[2] = 1 THEN
  83.       SB_CallSub(main::sb1, event{hex_event}[1])
  84.     ELSE IF event{hex_event}[2] = 2 THEN
  85.       SB_CallSub(main::sb2, event{hex_event}[1])
  86.     END IF
  87.     IF Iup::GetActionName() = "CLOSE_CB" THEN threads -= 1
  88.   END IF  
  89.   SB_msSleep(250)
  90. WEND
  91.  
  92. Iup::Close()
  93. SB_Destroy(sb2)
  94. SB_Destroy(sb1)
  95.  

SBx_T1 - T2 is the same
Code: ScriptBasic
  1. ' SBx_buttons Example (Thread 1)
  2.  
  3. IMPORT mt.bas
  4. IMPORT iup.bas
  5. IMPORT "SBx"
  6.  
  7. SUB btn1_clicked
  8.   PRINT "Thread 1 Button 1 Pressed\n"
  9.   PRINT "Which Mouse Button: ",CHR(Iup::GetBtnPressed()),"\n"
  10.   PRINT "Button Up/Dn State: ",Iup::GetBtnState(),"\n"
  11. END SUB
  12.  
  13. SUB btn2_clicked
  14.   PRINT "Thread 1 Button 2 Pressed\n"
  15. END SUB
  16.  
  17. SUB btn3_clicked
  18.   PRINT "Thread 1 Button 3 Pressed\n"
  19. END SUB
  20.  
  21. SUB win_exit
  22.   ' Good-Bye
  23. END SUB
  24.  
  25. SUB main
  26.   win = DIALOG()
  27.   SETPROPERTIES win, "TITLE=\"SBx Thread 1\", SIZE=300x"
  28.   horzbox = HBOX()
  29.   SETPROPERTIES horzbox, "GAP=5"
  30.   btn1 = BUTTON()
  31.   SETPROPERTIES btn1, "TITLE=\"Button 1\", EXPAND=HORIZONTAL"
  32.   btn2 = BUTTON()
  33.   SETPROPERTIES btn2, "TITLE=\"Button 2\", EXPAND=HORIZONTAL"
  34.   btn3 = BUTTON()
  35.   SETPROPERTIES btn3, "TITLE=\"Button 3\", EXPAND=HORIZONTAL"
  36.   APPEND horzbox, btn1
  37.   APPEND horzbox, btn2
  38.   APPEND horzbox, btn3
  39.   APPEND win, horzbox
  40.   Iup::SetThreadCallback(win, "CLOSE_CB", "main::win_exit", 1)
  41.   Iup::SetThreadCallback(btn1, "BUTTON_CB", "main::btn1_clicked", 1)
  42.    Iup::SetThreadCallback(btn2, "ACTION", "main::btn2_clicked", 1)
  43.   Iup::SetThreadCallback(btn3, "ACTION", "main::btn3_clicked", 1)
  44.   SHOW win
  45. END SUB
  46. mt::SetVariable("sb1_loaded","OK")
  47.  
« Last Edit: May 25, 2015, 06:54:23 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBT IUP Threaded
« Reply #40 on: May 26, 2015, 02:09:22 AM »
I have been doing some reliability testing and noticed that I need to access the Iup event loop after creating a dialog and before creating another. I setup a test where the main (host) dialog buttons start the threaded versions with a trip to the event loop once done. This method seems the most stable. I think I'm close to obtaining the optimal SB threading environment without having to tweak IUP/Gtk for threading.
« Last Edit: May 26, 2015, 10:22:51 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBT Threaded - SDL_gfx
« Reply #41 on: May 26, 2015, 01:36:57 PM »
I thought I would see if I could get the SDL_gfx extension module working in a threaded mode. It seems to work but the second thread replaces the the alpha_circles with the alpha_bezier example. I need to figure out how to create separate windows for each thread. Other than that, the loop grabbing keystrokes from the host script seems to be working.

sdlmain.sb
Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3. IMPORT gfx.inc
  4.  
  5. SUB SB_Wait(mtvar)
  6.   WHILE mt::GetVariable(mtvar) <> "OK"
  7.     SB_msSleep(5000)
  8.   WEND
  9. END SUB
  10.  
  11. sb1 = SB_ThreadStart("alpha_circles.sb", undef, "/etc/scriba/basic.conf")
  12. SB_Wait("sb1_loaded")
  13. SB_CallSub sb1, "main::main"
  14.  
  15. sb2 = SB_ThreadStart("alpha_bezier.sb", undef, "/etc/scriba/basic.conf")
  16. SB_Wait("sb2_loaded")
  17. SB_CallSub sb2, "main::main"
  18.  
  19. threads = 2
  20.  
  21. WHILE threads
  22.   keypressed = gfx::KeyName(1)
  23.   IF  keypressed = "+escape" THEN threads -= 1
  24.   SB_msSleep(250)
  25. WEND  
  26.  
  27. gfx::Close()
  28. SB_Destroy(sb1)
  29. SB_Destroy(sb2)
  30.  
  31. END
  32.  

alpha_circles.sb
Code: ScriptBasic
  1. ' ScriptBasic GFX - Alpha Circles
  2.  
  3. IMPORT mt.bas
  4. IMPORT gfx.inc
  5.  
  6. SUB main
  7.   scrn = gfx::Window(640, 480, "ScriptBasic GFX - Alpha Circles")
  8.   ' Random Value Arrays
  9.  RANDOMIZE(gfx::Time())
  10.   FOR i = 0 TO 512
  11.     rx[i] = RND() % 640
  12.     ry[i] = 60 + RND() % 480 - 80
  13.     rz[i] = RND() % 64
  14.     rr[i] = RND() AND  255
  15.     rg[i] = RND() AND  255
  16.     rb[i] = RND() AND  255
  17.     af = rx[i] / 640
  18.     ra[i] = INT(255 * af)
  19.   NEXT
  20.    
  21.   ts = gfx::Time()
  22.   FOR i = 0 TO 512
  23.     gfx::filledCircleRGBA scrn, rx[i], ry[i], rz[i], rr[i], rg[i], rb[i], ra[i]
  24.   NEXT
  25.   te = gfx::Time()
  26.   gfx::stringColor scrn, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0xffffffff
  27.   gfx::Update
  28. END SUB
  29. mt::SetVariable("sb1_loaded","OK")
  30.  

« Last Edit: May 26, 2015, 04:47:10 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: SBT Threaded - SDL_gfx
« Reply #42 on: May 26, 2015, 08:30:50 PM »
It looks like I'm returning the handle for the screen and passing it along to the other functions. For some reason SDL is sharing a window when threaded. Even if I don't enter the SDL event loop, the second thread overwrites the first. (no errors) I can start a SDL based script in the same console as a background job and run the second in foreground and see two windows.

I found an article on multiple SDL windows. I don't know if I want to go though all the trouble of create multiple windows and render surfaces to find out there is some other threading issue. What I've be able to pick up on threading SDL is don't.

It looks like only SDL 2 supports multiple windows.

Quote
Remember SDL_SetVideoMode()? It's completely gone. SDL 2.0 allows you to have multiple windows, so the old function didn't make sense any more.

So you might have had something like this:

Toggle line numbers

SDL_WM_SetCaption("My Game Window", "game");
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN | SDL_OPENGL);

Which is now this:

Toggle line numbers

SDL_Window *screen = SDL_CreateWindow("My Game Window",
                          SDL_WINDOWPOS_UNDEFINED,
                          SDL_WINDOWPOS_UNDEFINED,
                          640, 480,
                          SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);

You can see that this maps pretty closely to 1.2. The difference is that you can have multiple windows (if you want), and you can control them more. SDL_WM_SetCaption() is gone, because we want to allow each window to have its own title (you can change it later with SDL_SetWindowTitle()), and we want to let you specify a window position (or, in this case, use SDL_WINDOWPOS_UNDEFINED since we don't care where the system places it. SDL_WINDOWPOS_CENTERED is also a good choice).

Here is my SDL windows creation code.

Code: C
  1. besFUNCTION(gfx_Window)
  2.   DIM AS int width, height;
  3.   DIM AS Uint32 videoflags;
  4.   DIM AS Uint8  video_bpp;
  5.   DIM AS const char *title;
  6.   DIM AS const SDL_VideoInfo *info;
  7.   besARGUMENTS("ii[z]")
  8.     AT width, AT height, AT title
  9.   besARGEND
  10.   IF (title EQ NULL) THEN_DO title = "";
  11.   IF (SDL_Init(SDL_INIT_VIDEO) < 0 ) THEN
  12.     PRINT_FILE (stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
  13.     exit(1);
  14.   END_IF
  15.   atexit(SDL_Quit);
  16.   info = SDL_GetVideoInfo();
  17.   IF (info->vfmt->BitsPerPixel > 8) THEN
  18.     video_bpp = info->vfmt->BitsPerPixel;
  19.   ELSE
  20.     video_bpp = 16;
  21.   END_IF
  22.   videoflags = SDL_SWSURFACE | SDL_SRCALPHA | SDL_RESIZABLE | SDL_DOUBLEBUF;
  23.   IF ((screen = SDL_SetVideoMode(width,height,video_bpp,videoflags)) EQ NULL ) THEN
  24.     PRINT_FILE (stderr, "Couldn't set %ix%i %i bpp video mode: %s\n",width,height,video_bpp,SDL_GetError());
  25.     exit(2);
  26.   END_IF
  27. //SDL_SetAlpha(screen, SDL_SRCALPHA, 0);
  28.   SDL_SetAlpha(screen, 0, screen->format->alpha);
  29.   SDL_WM_SetCaption(title, 0);
  30.   SDL_EnableUNICODE(SDL_ENABLE);
  31.   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
  32.   besRETURN_LONG(screen);
  33. besEND
  34.  

« Last Edit: May 26, 2015, 08:52:01 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
Re: SBT Threaded - SDL_gfx
« Reply #43 on: May 26, 2015, 09:38:38 PM »
In an effort to see something rewarding for my efforts, here is 4 alpha_circle.sb threads running in the same window and their times.

Note: This example does not show multi-threading. Each thread executes one after the other.  :-\

Code: ScriptBasic
  1. IMPORT mt.bas
  2. IMPORT sbt.inc
  3. IMPORT gfx.inc
  4.  
  5. SUB SB_Wait(mtvar)
  6.   WHILE mt::GetVariable(mtvar) <> "OK"
  7.     SB_msSleep(2500)
  8.   WEND
  9. END SUB
  10.  
  11. sb1 = SB_ThreadStart("alpha_circles.sb", undef, "/etc/scriba/basic.conf")
  12. SB_Wait("sb_loaded")
  13. SB_CallSub sb1, "main::main"
  14.  
  15. sb2 = SB_ThreadStart("alpha_circles.sb", undef, "/etc/scriba/basic.conf")
  16. SB_Wait("sb_loaded")
  17. SB_CallSub sb2, "main::main"
  18.  
  19. sb3 = SB_ThreadStart("alpha_circles.sb", undef, "/etc/scriba/basic.conf")
  20. SB_Wait("sb_loaded")
  21. SB_CallSub sb2, "main::main"
  22.  
  23. sb4 = SB_ThreadStart("alpha_circles.sb", undef, "/etc/scriba/basic.conf")
  24. SB_Wait("sb_loaded")
  25. SB_CallSub sb4, "main::main"
  26.  
  27. gfx::Close()
  28.  

alpha_circles.sb
Code: ScriptBasic
  1. ' ScriptBasic GFX - Alpha Circles
  2.  
  3. IMPORT mt.bas
  4. IMPORT gfx.inc
  5.  
  6. SUB main
  7.   scrn = gfx::Window(640, 480, "ScriptBasic GFX - Alpha Circles")
  8.   ' Random Value Arrays
  9.  RANDOMIZE(gfx::Time())
  10.   FOR i = 0 TO 512
  11.     rx[i] = RND() % 640
  12.     ry[i] = 60 + RND() % 480 - 80
  13.     rz[i] = RND() % 64
  14.     rr[i] = RND() AND  255
  15.     rg[i] = RND() AND  255
  16.     rb[i] = RND() AND  255
  17.     af = rx[i] / 640
  18.     ra[i] = INT(255 * af)
  19.   NEXT
  20.    
  21.   ts = gfx::Time()
  22.   FOR i = 0 TO 512
  23.     gfx::filledCircleRGBA scrn, rx[i], ry[i], rz[i], rr[i], rg[i], rb[i], ra[i]
  24.   NEXT
  25.   te = gfx::Time()
  26.   ' gfx::stringColor scrn, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0xffffffff
  27.  PRINT "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds.\n"
  28.   gfx::Update
  29. mt::SetVariable("sb_loaded","DONE")
  30. END SUB
  31. mt::SetVariable("sb_loaded","OK")
  32.  


jrs@laptop:~/sb/sb22/sbt$ time scriba sdlmain.sb
Time: 0.0450 Seconds.
Time: 0.0230 Seconds.
Time: 0.0240 Seconds.
Time: 0.0190 Seconds.

real   0m0.308s
user   0m0.160s
sys   0m0.004s
jrs@laptop:~/sb/sb22/sbt$


Here is what it looks like if I were to run it as a normal SB script.


« Last Edit: May 26, 2015, 10:57:22 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3510
    • ScriptBasic Open Source Project
SBT Linux 64 bit build 2
« Reply #44 on: May 26, 2015, 11:34:22 PM »
For those running 64 bit Linux (compiled on Ubuntu 14.04) I have attached the latest build of the SBT and updated IUP extension modules. This version supports threaded IUP dialogs.

FYI: For best results, threaded IUP dialogs should be launched from the main script IUP dialog.
« Last Edit: May 27, 2015, 12:04:39 AM by John »