Diese Seite mit anderen teilen ...

Informationen zum Thema:
Forum:
WinDev Forum
Beiträge im Thema:
23
Erster Beitrag:
vor 3 Jahren
Letzter Beitrag:
vor 3 Jahren
Beteiligte Autoren:
Arekusei Timakobu, Alexandre Leclerc, Stewart Crisler

Work with threads - **solved**

Startbeitrag von Arekusei Timakobu am 27.01.2015 16:21

There is a main UI thread. It starts 2 "subthreads". One is used to show Motion JPEG on Image control of UI thread and other is used for getting some other information and displaying it on UI too. Below sample code:

Main thread (UIWindow)

Event(ProcessImageFrame,UIWindow..Name,"ProcessImageFrame")


Initialize Code: (started when window is opened)
ThreadExecute("Thread2",threadNormal,UpdateServerInformation)


BTN_Play_Click (started when button is clicked)

ThreadExecute("Thread1",threadNormal,ProcessMedia)



PROCEDURE ProcessImageFrame(uMessage,wParam,lParam)

// code for create Image and display it
Multitask(-100)
ThreadSendSignal("Thread1")


Thread 1


PROCEDURE ProcessMedia

WHILE True
// reading HTTP response with image raw content
PostMessage(Handle(UIWindow),"ProcessImageFrame",Content,Length)
ThreadWaitSignal()
Multitask(-100)
END


Thread 2


PROCEDURE UpdateServerInformation

WHILE True
// getting server information
// display on UI
Multitask(-100)
END



The problem is when I click button and "Thread 1" is executing ("Thread 2" is already working") then "Thread 2" is stopped and no server information is updated. The main thread works only with "Thread 1", i.e. data is read and posted to main window via PostMessage, then this thread waits for a signal from UI thread. In the main thread those data is prepared to display and is displayed and send signal to "Thread 1" to continue... And so on. "Thread 2" is silent :( When "Thread 1" is stopped then "Thread 2" continue its work. Could someone help me? Or give advise how to work with threads correctly? Thanx.

Antworten:

Re: Work with threads

Hi Arekusei,

I think that all this is a bit complicated for a simple task. You could use only one thread. In that thread you look to get status information. When status changes (when you have an image), then simply call the main form procedure to update the status using ExecuteMainThread(). You should be in business very simply.

In fact, you could even use an automatic thread (timer option in the procedure - top-right on the procedure name header line) to do this task.

It's not that this is not possible to do it they way you did, but by what I can see, having no source code, I think you do not understand well the threading model and the use of signals. (I might be wrong, but the above code does not look good in the logic nor in the use. I might also not really understand what you try to achieve and so why this is structured the way you tried to do.)

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 27.01.2015 16:46

Re: Work with threads

Quote
Alexandre Leclerc
I think that all this is a bit complicated for a simple task. You could use only one thread. In that thread you look to get status information.

I think you are right in this case but the fact is that I need to read HTTP media stream, i.e. I get request to HTTP and in result I get a multipart data:

Content-Type: multipart/mixed; boundary=--SomeBoundary

--SomeBoundary
Content-Type: image/jpeg
Content-Length: 1209
..... data....

--SomeBoundary
Content-Type: image/jpeg
Content-Length: 1209
..... data....

This stream is MUST BE read in infinite loop in SEPARATE thread otherwise my application (MainThread) will be blocked, agree? Also I use automation procedure for UpdateServerUsage but I had a problem. When timeout has expired and automated procedure starts to work the UI thread is died. So I noticed that automated procedures does not "live" with thread together.

von Arekusei Timakobu - am 27.01.2015 18:01

Re: Work with threads

I did a presentation for WXLive on October 10th of 2014 where I demonstrated multithreading with UI updates using the example of a ticket booth. I use queue's to handle the communication between threads. You might find something useful in that presentation. The WXLive stuff has been migrated to Youtube. Search for WXLIVE MULTITHREAD.

As stated above, it's a complicated topic.

Stewart Crisler

von Stewart Crisler - am 27.01.2015 18:25

Re: Work with threads

Hi Arekusei,

The http result can be read in the same thread that makes the request. If you want, you can indeed call another thread to manage the data. I just tried to make is simpler for you. When you start working with thread and you do not completely know how the mechanic is working, you can make a lot of messy code. So you start very simple (even if not optimal) and then when it works fine, you can try to add complexity.

The main thread will be "blocked" if it has a lot of data to parse. In you example, the same thread that receives the http request could also extract and interpret the data when there is data to process. Then it could save that data somewhere, call the main thread to display the data and loop again to wait for new data to come in. This would be very good like that.

Automatic procedure, if you select Thread, will not cause any "lock" in your main thread. But you have less control over the process in this way. In you case, the process could start right after application start and would be good enough I guess.

Based on what you described, there is probably a coding problem in how your threads are made or are working to have the problems you describe. For example, maybe your threading model is not configured correctly (see ThreadMode http://doc.pcsoft.fr/en-US/?3077028). Many little things to look at. Threads a great but not easy to get at first. You probably already read the help, but the more I read, the better I understand, usually: http://doc.windev.com/en-US/?3077004

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 27.01.2015 18:29

Re: Work with threads

Quote
Alexandre Leclerc
The http result can be read in the same thread that makes the request.

Maybe I explain badly... My http result have no limited value in bytes. I.e. when I asked some HTML page, yes - there is no problem. I just read 100 or 1000 bytes but in my case I get infinite data stream (jpeg frames or even video stream) that I need to display on fly. Imagine water stream, you can't force it to stop, you can just use bucket fill it and "process it". But if you will use bucket by himself you can't do anything else, so you need someone (another thread) to help you. The code is looks like:


let request


von Arekusei Timakobu - am 27.01.2015 20:33

Re: Work with threads

Btw, below a sample code on C# (cut). Here it is the example of what I need.


// create and start new thread
thread = new Thread(new ThreadStart(WorkerThread));
thread.Name = source;
thread.Start();

// Thread entry point
public void WorkerThread()
{
byte[] buffer = new byte[bufSize]; // buffer to read stream
while (true)
{
// create request
req = (HttpWebRequest) WebRequest.Create(source);
// set login and password
if ((login != null) && (password != null) && (login != ""))
req.Credentials = new NetworkCredential(login, password);
// get response
resp = req.GetResponse();

// check content type
string ct = resp.ContentType;
if (ct.IndexOf("multipart/x-mixed-replace") == -1)
throw new ApplicationException("Invalid URL");

// get boundary
ASCIIEncoding encoding = new ASCIIEncoding();
boundary = encoding.GetBytes(ct.Substring(ct.IndexOf("boundary=", 0) + 9));
boundaryLen = boundary.Length;

// get response stream
stream = resp.GetResponseStream();
// loop
while ((!stopEvent.WaitOne(0, true)) && (!reloadEvent.WaitOne(0, true)))
{
// read next portion from stream
if ((read = stream.Read(buffer, total, readSize)) == 0)
throw new ApplicationException();

... some code ...
// image at stop (if event is subscribed)
if (NewFrame != null)
{
Bitmap bmp = (Bitmap) Bitmap.FromStream(new MemoryStream(buffer, start, stop - start));
// notify client (send event to)
NewFrame(this, new CameraEventArgs(bmp));
// release the image
bmp.Dispose();
}
}
}


von Arekusei Timakobu - am 27.01.2015 20:41

Re: Work with threads

Hi again Arekusei,

Ok, now I understand better where you are going. I still do not get how your processes are split. Is one thread get HTTP responses and another managing it's data? If so why can't one do it all? If not, how are you passing the data between both thread? Or are you using multiple threads to process the data? Finally, how do you ask the main form to display the image? But maybe all this is working already. (There are many parts that work together and in many of them something can go wrong.)

But to come back to your original question, did you check the threading model? I had troubles in the past because it was no right. I'm quite sure this is due to that, or a maybe a wrong use of the ThreadWaitSignal()... in fact, what signal is your thread waiting before processing more data?

If the threading model is right, you can have multiple threads working independently or together without blocking each other. The only blocking you can have is a thread waiting for something never happening (like a signal that never comes in or has already passed by, etc.)

I hope this can help you a little bit. Sorry if not.

Best regards,
Alexandre Leclerc

PS. My comment about automatic procedures is that they can be threads, but managed by WinDev (so less control to the programmer, but easier to use). Indeed you do not need them if you work directly with thread.

von Alexandre Leclerc - am 27.01.2015 20:57

Re: Work with threads

Hi Arekusei,

The same thread is doing the HTTP request and also processing the data, then sends an image to the main application for display. This is what I was trying to tell in my first message. One thread does all that.

I guess all the display part is working well.

This thread should work well and the other thread that sends the status information should also work in parallel at the same time. Just make sure the threading model is good.

Kind regards,
Alexandre Leclerc

von Alexandre Leclerc - am 27.01.2015 21:04

Re: Work with threads

Hi Alexandre.

I don't understand why you don't understand :)

Quote

The same thread is doing the HTTP request and also processing the data, then sends an image to the main application for display.

How?! Imaging... a window... on windows message loop...

The simple (sample) code:


PROCEDURE WIN_MAIN

Info("The window has been opened. After click button OK the procedure ProcessMediaStream will be run!")

ProcessMediaStream() // the code for readin of data stream

Info("The ProcessMediaStream is running. User can click any buttons and other controls. User can move and resize window")


PROCEDURE ProcessMediaStream()

WHILE True // infinite loop!
...
END



Please, explain me how I can get the second Info message, how can I click on buttons etc if the procedure ProcessMediaStrem contains infinite(!) loop?! This procedure will not return control to application after its completion, i.e. never because I repear the loop is infinite.

Quote
But to come back to your original question, did you check the threading model?

What do you mean talking about threading model? It seems I don't completely understand.

Quote
I still do not get how your processes are split. Is one thread get HTTP responses and another managing it's data? If so why can't one do it all?
I have already explained it again above.. ;) The main thread is the main window that must be accessible at any time(!). User must click tabs, buttons, information in textboxes must be changed with some defined time interval. How it may be possible (using your suggestion with single thread) if main window calls the procedure with infinite loop? That it is why I need the second thread that reads the data independently! I.e.



PROCEDURE WIN_MAIN

Info("The window has been opened. After click button OK the procedure ProcessMediaStream will be run!")

ThreadExecute(ProcessMediaStream,threadNormal,"ProcessMediaStream") // the code for reading of data stream

Info("The ProcessMediaStream is running. User can click any buttons and other controls. User can move and resize window")


In this code I see the second Info message and the data will be read in secondary thread and those infinite loop will not affect on my UI (main) thread. Am I right?

ThreadWaitSignal and ThreadSendSignal I use because I can't read next data portion from data stream if the previous data hast not be displayed on Image control of main window (main UI thread).

I would like to see your example of code that you suggest but the single thread can't serve my functionality w/o variants.

P.S. All that I need if someone explain me on example how can I use 2 (or 3 threads) for: 1.having total control of main UI thread (w/o blocking),
2.having ability to read pemanently coming data, process it and display on main window (asynchronously)
3. having ability to make requsts to server and display other data on the main window asynchronously.

The Trace statement must be log something like this:

Proc1 - Getting image data... wait
Proc2 - Displaying image data...
Proc1 - Getting image data... continue
Proc1 - Getting image data... wait
Proc2 - Displaying image data...
Proc1 - Getting image data... continue
Proc3 - Getting server information data...
Proc1 - Getting image data... wait
Proc2 - Displaying image data...
Proc1 - Getting image data... continue
Proc1 - Getting image data... wait
Proc2 - Displaying image data...
Proc3 - Getting server information data...

von Arekusei Timakobu - am 28.01.2015 07:46

Re: Work with threads

Well.. I leave only main thread and the secondary thread. Secondary thread read data and PostMessage to main window to display prepared image. I've removed ThreadWaitSignal and ThreadSendSignal, i.e. I've done as in above C# example. All works fine... but I need asynchronously to make additional request to display server usage info. If I make the requesting procedure as automated procedure with some timeout then when this procedure starts to work my main window is dying... i.e. there is a problem with threads and automated procedures (I think it is linked with timer). So how can solve this problem? Do I need to use another thread?

von Arekusei Timakobu - am 28.01.2015 08:40

Re: Work with threads

Lets' continue.. I created an automared procedure UpdateServerData that is running in a thread.


PROCEDURE UpdateServerData()

WHILE True
gServerData = RequestServerData()
ExecuteMainThread(DisplayServerData)
Multitask(-500) // delay 5 sec with returning control to windows and WDLanguage
END

PROCEDURE DisplayServerData()

EDT_GlobalMemory = gServerData.p_sGlobalMemory // display data
...


When I only start the main thread the UpdateServerData is working fine (data is refreshed). As I only start thread with readin of stream video data the automated procedure UpdateServerData is stopped. :(

Please help me to synchronize threads...

von Arekusei Timakobu - am 28.01.2015 08:58

Re: Work with threads

Hi Arekusei,

Please, take the time to do a very simple test project. Create an empty form, put a Multi-Line Text control in it and make it bid. Then put the following code in the form:



// In the declaration of the window:
PROCEDURE MyWindow()

StartThread1()
StartThread2()

// Add a procedure named as follow
// Configure the procedure (timer option) to run as a THREAD WITHOUT HFSQL needs
//
// Automatic Procedure:
// The procedure is performed manually during a call in the code
// It will run in a thread (without needing to call the ThreadExecute function) without using HFSQL
//
PROCEDURE StartThread1()

WHILE True
ExecuteMainThread(Display,"Thread 1 " + Now())
ThreadPause(50)
END

// Add a procedure named as follow
// Configure the procedure (timer option) to run as a THREAD WITHOUT HFSQL needs
//
// Automatic Procedure:
// The procedure is performed manually during a call in the code
// It will run in a thread (without needing to call the ThreadExecute function) without using HFSQL
//
PROCEDURE StartThread2()

WHILE True
ExecuteMainThread(Display,"Thread 2 " + Now())
ThreadPause(70)
END

// Then add the following standard procedure:
PROCEDURE Display(s is string)

SAI_SansNom1 += [CR] + s // SAI_SansNom1 is the multi-line text control


Now I run this code and both thread are working well together without blocking the main interface (main thread). This is a basic thread experience. Then from there you add complexity.

Your above project should be as simple as that to work. StartThread1 is the thread that get and process web data to display images. StartThread2 is the one sending or getting server status.

If you want to use manual thread, that is fine. But start simple, it will help you identify the problem in your code. I'm sorry if I do not understand what you do, maybe you do not understand what I try to express also. So I do all my best to give you tools that will help you solve your problem. I do not have your source code.

Hope this can help.

Kind regards,
Alexandre Leclerc

von Alexandre Leclerc - am 28.01.2015 14:38

Re: Work with threads

Hi Arekusei,

You see, some code in your code was causing issues. So my guess is that some other code is also causing issues. When you try to identify a problem, always reduce the problem to its simplest expression. This is why I asked you in another post to build a very simple thread app. Starting from there you can add complexity.

Both thread should work well together without disturbing the other. The main thread should not have blocking actions (of course).

Kind regards,
Alexandre Leclerc

von Alexandre Leclerc - am 28.01.2015 14:41

Re: Work with threads

Hi again Arekusei,

Quote

How?! Imaging... a window... on windows message loop...


When I speak of one thread, I do not speak of the main thread. I say that one thread is doing all the blocking job and that is it good enough. If you look at the C# code, this is exactly what it is doing.

Main thread (application): calls Thread_GetTheDataFromTheWeb() and also calls Thread_GetTheStatusAndSendStatusInfo() and the threads are calling DisplayImages() or DisplayStatus() of the main thread. Voilà!

You do not need a second data processing thread nor signals. If you want, complexify later. For now just concentrate to read the data and send images to the main application in an infinite loop, in one thread that does only that. HTTP + DataStream + Send to main application thread. Then later, when this works, just try to add some more complexities if you need to. The images could be stored in an array of images and just leave it to the main application to decide when displaying them (buffer principle).

The very small project example should answer your questions. I'm sure you will get the picture. Simple threads can do the job you want. I even thing that the data thread could also send status notifications to the server after it has received and processed the previous data. But it can be in two threads without a problem.

I really hope all this can be of some help to you.

Best regards and good luck,
Alexandre Leclerc

von Alexandre Leclerc - am 28.01.2015 14:51

Re: Work with threads

Quote
Alexandre Leclerc
Please, take the time to do a very simple test project.

Ok. I will try this code. How can I pass parameter to main thread to display data on main window? Or is it possible to update controls from threads (I am not sure)? I need to pass Image variable or array of int or object.

von Arekusei Timakobu - am 28.01.2015 15:03

Re: Work with threads

Hi Arekusei,

Read my other posts, this will answer your question. Test the above code, this will also answer your question about how to pass data. This is one way to do it (and a simple one).

In a nutshell: No you can't update main GUI from a thread. For data, just create a proc that has an image as parameter, or an integer. The above example passes a string.

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 28.01.2015 15:08

Re: Work with threads

Alexandre, thank you for your help!

I've used your example and create 2 automated procedures running in threads. The single difference is that one of "long" procedure is a method of class so I've done so


WHILE True
ExecuteMainThread(WIN.DisplaySomeData,nFrameCount,nFrameSize)
END


The first threaded procedure is run on window start the second after button click. When I run the application the first thread is running. When I click the button to start 2nd thread this thread is running but 1st thread become waiting. At lease I don't see answer from it. When I stop 2nd thread the first thread continue its work. This is a problem :)

von Arekusei Timakobu - am 28.01.2015 16:12

Re: Work with threads

Hi Arekusei,

I'm sorry but I can't help you above that since I do not know how your code is organized (threads, non-thread) and what is the code. As my example shows, two threads are not blocking each other and can work very well together.

Now, is the second thread stopping the first one by a line of code? Is it playing with signals or critical sections? A critical section can block a thread. How is called your first thread and how is called the second one? Do they have different name. Are you using critical sections and if so, is the ThreadMode() set correctly?

The "long" code is called from the thread or called to be executed by the main thread? The While True for display does not look correct to me do you mean:

WHILE True
// http request
// parse data
ExecuteMainThread(...)
// loop again to receive and parse more data
END


or do you really mean:

WHILE True
ExecuteMainThread(...)
END


In that case, (and I don't know anything about your code), this looks wrong. Anyway.

You must identify the source of the problem by a thorough analysis and unfortunately nobody can do it for you. It should work quite simply if the code is correct.

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 28.01.2015 16:32

Re: Work with threads

Hi Aleandre.

Here it is as it looks:

End of initialization WIN_MS


ProcessServerUsage() // automated procedure


BTN_Play click


ProcessImageStream(RADIO_MediaType) // automated procedure



PROCEDURE ProcessServerUsage()
WHILE True
gclServer = SomeAPI.GetServerInfo()
ExecuteMainThread(DisplayServerUsage,gclServer)
ThreadPause(300)
END



PROCEDURE ProcessImageStream(MediaType)
IF MediaType = "MJPEG"
SomeAPI.GetMJPEG('Camera',...)
END



SomeAPI is Class
PROCEDURE GetMJPEG(Camera,...)
// request and process response
WHILE True
// reading from response stream
sHeader = GetMultipartHeader() // read header
arrReadBuffer = StreamReader.Read(...) // read content part
// some light actions
...
// if content is image
IF ContentTypeBase = "image"
nFrameCount++
clImage is Image = GetBufferFromArray(arrReadBuffer) // use Transfer for copy array to buffer
ExecuteMainThread(WIN_VMS.DisplayMediaFrame,clImage,nFrameCount)
ThreadPause(50)
END
Trace(...)
END
END



PROCEDURE DisplayServerUsage(gclServer)
EDT_ServerName = ...
// Assign values from gclServer to screen controls
Trace(...)



PROCEDURE DisplayMediaFrame(clImage,nFrameCount)
IMG_MJPEG = clImage
STC_FrameCount = nFrameCount
Trace(...)


That's all. The method GetMJPEG is most "hard" place. It reads response stream from web server. It read about 100 bytes to process multipart header to define what content type is streamed and what the size of the multipart content. Then this size is read from stream and converted from array to buffer. After that buffer is used to load into Image variable and passed to main thread.

von Arekusei Timakobu - am 29.01.2015 07:18

Re: Work with threads

Hi Arekusei,

There is only one thing that makes me uncomfortable about your code and it is the use of a class object.

Here is an unverified supposition from me. (I have no specific real-world experience with this kind of code setup, so to say. You should confirm with the Free Technical Support.) I fear that the class instance might be blocking your threads because you try to execute two threads from within the same object instance. Your class methods are not GLOBAL and so WinDev might think that you want to execute two "same procedure/object" at the same time from threads. And so, only one thread at the time will be able to run. And this is exactly that behaviour you have right now.

So if that supposition is right you would have two solutions:

1 - Read the help file again and configure the ThreadMode() as I was explaining in my first posts. See "Processes of a WinDev application" in this help page: http://doc.windev.com/en-US/?3077004&name=principle_for_running_threads#limits_the_processes_performed_the_thread_ELTPARAGRAPHE000325

You will have to use critical sections to read and write your object's members and methods or properties that change the members. The threading model has to be set to threadCriticalSection. Then your class object will not block your both threads. (This is my supposition.)

or

2 - Make the class methods as GLOBAL procedures. I think it should, then, be considered as a normal procedure and make no problem without having to play with the ThreadMode() and critical sections. In that case, make the members you must interract with as PUBLIC GLOBAL too.

Another thing you might consider to do is simply testing your code in standard procedures instead of through a class. Then make it a class. By the way, why are you using a class object with non-global procedures for a thread? If it is to access specific config data? Then, as said in point 2, also make the required members PUBLIC GLOBAL and this will solve your problem. (I say that in case you simply use a class as a container for related procedures and common variables.)

I Hope this can finally solve your problems at once.

Best regards,
Alexandre Leclerc

von Alexandre Leclerc - am 29.01.2015 13:34

Re: Work with threads

Hi, Alexandre.

I re-read all you wrote me and you was right ponting me on incorrect threading mode. I've read the documentation about ThreaMode function and found out that default Automatic management of the critical sections force each procedure or method to be run by a single thread at a time. I've changed the threading mode to threadCriticalSection and now my secondary threads live in peace and harmony even without ExecuteMainThread call.

Thank you for your help!

von Arekusei Timakobu - am 30.01.2015 10:49

Re: Work with threads

Hi Arekusei,

I'm very glad for you that it is now working!

Now I want to recap a make a point clear:

- Both of your threads would have worked in perfect harmony if they were not considered to access the same "object" or "method" at the same time. (The proof is in the small test application I posted up there. And it looks like that my previous supposition was right since the ThreadMode() has solved the issue. Something new has just been learned.)

- You had to use the ThreadMode() with threadCriticalSection because both of your thread were non-global methods in a class object. But it would have not been required if the code was structured differently.

I just wanted to point it out to make sure you perfectly understand this very important little detail. This will help you greatly going on.

Also, as additional notes:

- Make sure to use critical sections if two parts of code in threads can read/write at any given time the same object or variable to avoid read/write collisions, if this is required in your processes. (Sometimes it is not required, and will not hurt to not use critical sections.)

- Use ExecuteMainThread() when you have to interact with the UI. Note that this will block the calling thread until the action has been done by the main thread. Then the calling thread will continue. (It is not required in many cases, but in other, yes.)

Best regards!
Alexandre Leclerc

von Alexandre Leclerc - am 30.01.2015 13:27
Zur Information:
MySnip.de hat keinen Einfluss auf die Inhalte der Beiträge. Bitte kontaktieren Sie den Administrator des Forums bei Problemen oder Löschforderungen über die Kontaktseite.
Falls die Kontaktaufnahme mit dem Administrator des Forums fehlschlägt, kontaktieren Sie uns bitte über die in unserem Impressum angegebenen Daten.