Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
2 questions...
#1
Hi Gintaras, hi all,

1. What is the QM way to do a C like do-while

do{
......
}(while(........)

loop?


2. I have a shell menu function that does file conversion.

function $files

str f
foreach f files
int ht=mac("sub.Convert" "" f)
mac "sub.End" "" ht

It works flawlessly, but as I have a powerful laptop, I'd like to use it multithreaded, i.e it would convert 
many files at the same time.

Can you steer me to the solution?

Thanks
#2
1.
rep
;... ;;code without 'continue'
;if(!...) break

2. Your code already does it. mac("sub.Convert" "" f) creates new thread. Don't know what the next line does.
But if there are many files, can create too many threads and make slightly slower than when the thread count matches the count of logical CPUs. Probably not a problem in most cases.
#3
Well, when I select multiple files for conversion in explorer, I can certify there is only conversion at a time with this macro, that is why i'd like to have 4 threads running at the same time, my laptop can handle this heavy duty....

The last function is useless and for testing purpose only, called when last file has been converted.
#4
Update: this code does give as much threads as wanted for conversion routine based on r variable.

Feel free to update and improve the code Gintaras


Code:
Select All      Help
function $files

;==========================================================================================
out
int r=0
int ht

;============================================================================================
str f
foreach f files
,r+1
,ht=mac("sub.Convert" "" f)
,if r=3
,,r=0
,,WaitForThreads 0 "MKV:Convert"
#5
Macro MKV
Code:
Select All      Help
out

;create list of files for testing
ARRAY(str) af; GetFilesInFolder af "q:\test"
str files=af

;==========================================================================================

int nThreads=4
__Handle sem=CreateSemaphore(0 nThreads nThreads 0)
str f
foreach f files
,wait 0 H sem
,mac("sub.Convert" "" f sem)
WaitForThreads 0 "MKV:Convert" ;;to avoid calling ReleaseSemaphore(closedHandle)


#sub Convert
function $f sem

atend sub.ReleaseSem sem

;thread code for testing
MES m.timeout=RandomInt(1 3); m.x=RandomInt(1 1000)
mes f "Convert" m


#sub ReleaseSem
function sem
ReleaseSemaphore(sem 1 0)
#6
Thanks

I have little remembrance about semaphore use, and did not think of them.

BUT
1. why you use :

WaitForThreads 0 "MKV:Convert" ;;to avoid calling ReleaseSemaphore(closedHandle)????

2. Why use a sub function to release the semaphore (ReleaseSem) and not do it directly at the end of the convert function?

3 Why use atend and no call the sub function ReleaseSem directly at the end of the convert function?
#7
1. The main macro exits when it started the last 4 threads. When it exits, sem destructor calls CloseHandle, making the handle invalid and its numeric value subject to use for another handle. If the main thread does not wait until other threads exit, other threads call ReleaseSemaphore with invalid or another (value reused) handle.

2, 3. If you know that threads never ever return or throw exception without calling ReleaseSemaphore, then call ReleaseSemaphore at the end instead of atend/#sub. Another way to ensure that ReleaseSemaphore is always called at the end - create a class that calls ReleaseSemaphore in destructor, and declare a variable of that class in the thread.
#8
Improved version. Previous version does not work well when the main macro started again while some old threads are still not ended. Also now is used class instead of atend.

Macro MKV
Code:
Select All      Help
out

;create list of files for testing
ARRAY(str) af; GetFilesInFolder af "q:\test"
str files=af

;==========================================================================================

__Handle+ g_sem2257; lock() if(g_sem2257=0) int nThreads=4; g_sem2257=CreateSemaphore(0 nThreads nThreads 0)
str f
foreach f files
,wait 0 H g_sem2257
,mac("sub.Convert" "" f)


#sub Convert
function $f

#compile "__SemaphoreReleaser"
SemaphoreReleaser semRel=g_sem2257

;thread code for testing
MES m.timeout=RandomInt(1 3); m.x=RandomInt(1 1000)
mes f "Convert" m


Macro __SemaphoreReleaser
Code:
Select All      Help
class SemaphoreReleaser -_h

Member function SemaphoreReleaser.
Code:
Select All      Help
ReleaseSemaphore _h 1 0
Note: it is Member function, and its name ends with period.
#9
>>1. The main macro exits when it started the last 4 threads. When it exits, sem destructor calls CloseHandle, making the handle invalid and its numeric value >>>subject to use for another handle. If the main thread does not wait until other threads exit, other threads call ReleaseSemaphore with invalid or another >>>(value reused) handle.

I got it, like C++ thread function join().

2, 3. If you know that threads never ever return or throw exception without calling ReleaseSemaphore, then call ReleaseSemaphore at the end instead of atend/#sub. Another way to ensure that ReleaseSemaphore is always called at the end - create a class that calls ReleaseSemaphore in destructor, and declare a variable of that class in the thread.

I think that KISS principle makes me carry on with the old code

#sub ReleaseSem
function sem
ReleaseSemaphore(sem 1 0)

Thanks.
#10
Reading much since my post and your code, I see that Semaphore, mutexes and lock are individual entities in C++ and seem mixed in Qm implementation.

Can you tell me the QM way for each one?
#11
QM does not have classes for semaphores, mutexes and critical sections. In lock by default is used fast code similar to critical sections; or can be used mutex. In this macro I directly used Windows API functions CreateSemaphore, ReleaseSemaphore.


Forum Jump:


Users browsing this thread: 1 Guest(s)