Solved

How do I make a property/variable common to multiple asynchronous threads?

Posted on 2006-10-27
8
287 Views
Last Modified: 2010-04-23
I have an application that is using background workers and an asynchronous socket system.

on my form, I have a class that I created that stores my client socket object and it triggers events when data comes in, etc.
I also have labels, properties, and variables populate as communication occurs.

For example:

I have a variable that is global to my form called "Response"
I have another global variable called ReceiveTimeout
I have a method called "send_data"
I have a method called "Data_Received" which is the handler of my socket object receive event.


in my send method I do this:


    Response = ""
    MyObject.Send(ServerAddress, "MyData")

    Do
          If System.Environment.TickCount - ReceiveTimeout > 30000 Then Exit Do
          if Response = "Done" then exit do
    Loop


Pretty simple.... send a command to the server and wait for it to reply with "done" or time out after 30 seconds.
if my Data_Received event, I have this:

    if IncommingData.StartsWith("***Progress:") then
          ' we got a progress report from the server, so update the progress label with the message.
         UpdateStatus (IncommingData.remove(0,13))
         ' Reset the time out so that we don't end prematurely
         ReceiveTimeout = System.Environment.TickCount
    else
          ' We got a command response from the server
          Response = IncommingData
    end if


And my update status routine:

    Private Delegate Sub UpdateStatusDelegate(ByVal Text As String)
    Private Sub UpdateStatus(ByVal Text As String)
        If Me.InvokeRequired Then
            Dim d As New UpdateStatusDelegate(AddressOf UpdateStatus)
            Me.Invoke(d, Text)
            d = Nothing
        Else
            lblStatus.Text = Text
        End If
    End Sub



So, the plan was this. Send a command through the socket port, and asynchronously wait for a command to come it, or time out after 30 seconds.
Once the command comes into the buffer, the object will raise the event that will populate the response variable and thus, when data_received routine finishs executing, then send method will see the change and exit the do loop without timing out or error.

The PROBLEM is that the datarecieve event fires, and populates the response variable just fine. But the send method thread doesn't read it. The response value in the send method stays blank while the value of response in the data received method is that of the command response. At the same time, when I try to update the status of the label, the text value in the datareceived method is what I set it to, but in the send method the label text stays blank.

it is almost as if my global variables and properties and controls have duplicated for the alternative thread and are discarded when the setting thread is finished.


How can I get my data from one thread to the other?
I am using VS 2005
0
Comment
Question by:Mystify
  • 4
  • 2
  • 2
8 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 17821439
Why do you need synchronous send method? It should be asynchronous - send data and return immediately.
Your program design is mix of 2 styles: synchronous and asynchronous. Except of this, there is some background thread - what does it do?
Asynchronous socket classes allows to write program without worker threads. Socket implementation internally runs threads and raises event handlers in the program. Event handlers may be called in another threads and should use Invoke or BeginInvoke as your UpdateStatus function.

You need to redesign program algorithm to make it completely asynchronous. Some number of variavles and flags should define current program state. For example, program states can be:
Initial (in the beginning),
Waiting for Response (after send function is executed),
Other states, according to desired actions.

Data which can be accessed from different threads must be protected with SyncLock statement.

If you didn't see Microsoft asynchronous chat sample before, check it out:
http://www.microsoft.com/downloads/details.aspx?familyid=08e3d5f8-033d-420b-a3b1-3074505c03f3&displaylang=en

Download file VisualBasic.msi, install it and read sockets sample.
0
 
LVL 2

Author Comment

by:Mystify
ID: 17821591
I will take a look at that example.... but to make a long story short, there is the skinny.


I have a "server" application with facilitates communication between wireless devices and SQL Server.
The server is also response for scanning the network and updating the database depending on the state of various remote devices (custom hardware boards)

So, there is a background worker on the main form of my server which is designed to run the maintence routines and network scans while still allowing the user to interact with the GUI.... the background worker acts like a "client" on the network, but is running locally and is not interfering with the user.

Now, I have written a communication class that is completely asynchronous in both sending and receiving. However, when the user issues a command (either from the background worker, gui, or from a remote device), the user needs to wait so that a series of commands and actions can be executed on the server and the server responds that it's either completely successfully, or failed with a reason.

So the user clicks a button. The command is sent using the asynchronous send command. The program must now wait for a response from the server indicating if it is done processing.

So, I put an hourglass and enter a do loop while I want for the response. If I don't get any response from the server in 30 seconds, I time out and abort the proceedure. I can get 2 types of responses from the server, either a "Progress" message, which I use to inform the user of what is going on on the server side, as processing can actually take longer than 30 seconds, depending on the action - so by sending progress messages, it tells the client application the server is still there, and still processing, and to hold it's horses until it's done.
The other type of message is the command response message. This tells the client that the server has completed and it can now return control back to the user and update local information according to the results of the processing.

The send/recieve is asynchronus because I have a small animation of a progress bar (of sorts) on screen, with a label showing the user the the system is processing, and any progress messages from the server.


My problem is, once I send the command to the server, how do I get the software to wait until I get the server response while not completely locking the software up, but still allowing the ReceiveCallback to fire and thus raise the event to inform the calling form that data is now in it's buffer to be processed.

I have a ws_Receiving event that is raised in the ReceiveCallback  and I pass the data that came in.
I then look at the message and if it's a progress message, I update the label... and if it's a command response, I set the variable that will cause the initaiting thread to exit it's do loop. But the variables that are set in the ws_Receiving method do not carry over to my button click method.




 
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 17821661
I still think thst send function must be asynchronous. All time between sending request and receiving reply you can disable program interaction by some other way - disabling controls, showing progress dialog with Stop button etc.

Quick fix of your current algorithm:

    Do
          If System.Environment.TickCount - ReceiveTimeout > 30000 Then Exit Do

          Thread.Sleep(100)                    ' Optionally - to improve program UI responsiveless during waiting
          Application.DoEvents()              ' here Response variable is updated - otherwise events are not handled

          if Response = "Done" then exit do
    Loop
0
 
LVL 1

Accepted Solution

by:
super786 earned 500 total points
ID: 17821687
Without seeing your entire object structure, I can't be sure of your problem.  Can you post where your objects and methods are defined?  We know you have a form object, and MyObject (I'm guessing the wrapper for your client socket) is defined inside of it.  Or is it actually after it, but just in the same .vb file?  How do the two interact?  Your send method has an instance of MyObject (or is Send a shared method?).  Does MyObject ever get a callback reference to your form, or is MyObject declared WithEvents so that Form1 just catches its events?
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 2

Author Comment

by:Mystify
ID: 17821770
I have a form. This contains the background worker object that is trigger via a timer.
I have class in a seperate file. This is the "communication" class which does the interaction to my asynchronous socket object.
Then I have a generic dll project that is refferenced in my communication class which actually does all the async actions for communication to and from the actual socket object.


the actually SENDING of information TO the server from the clients IS asynchronous, as the "send" method in the communication class fire off command to the object. Once it goes, the program continues to execute. I need the method to continue to process in the send method until a response from the server is recieved telling the client which action to take.... show a message box telling the user of a failure, updating some icons to show status, whatever.



Also:

    Do
          If System.Environment.TickCount - ReceiveTimeout > 30000 Then Exit Do

          Thread.Sleep(100)                    ' Optionally - to improve program UI responsiveless during waiting
          Application.DoEvents()              ' here Response variable is updated - otherwise events are not handled

          if Response = "Done" then exit do
    Loop



This is more or less what I am doing. I have found that i can NOT use the Do events as it generates another error - but it doesn't matter as the do events doesn't help. And the sleep event doesn't matter either

But the problem is the response variable that exit's the do loop will NEVER EVER get set to DONE.

For some reason, when the data recieved event fires (on the form level) I set the response variable =  to "done", but the the value of response in the do loop has a value of "" and the value of response int he recieved event has  a value of "done"

The same variable
2 values - depending on the thread you are in.

My question is, how can I make one thread set the value of the variable so that other threads will pick up that same value?
so, in the case of the example the the "If Response = "Done" then" will evaluate to true, and thus exit the do and move on.



0
 
LVL 1

Expert Comment

by:super786
ID: 17822860
If the datareceived event is at the form level, and the send method is at the form level, and your Response string is defined in the declares section of your form, then I would look for either two instances of your form to be loaded, maybe one invisible, or an extra Response declaration that may be old and not deleted.  For the extra instance of the form, 1)  declare a shared integer in the declares section.  Increment it in the Sub New() of your form, then check it in your datareceived event.  If it is ever 2 or more, you have multiple instances (or just set a breakpoint on the InitializeComponent call.  It should only get hit once).  2) Just declare your Respone string as Shared.  If this works, then again you have multiple instances of your form open.

If neither of these help, you will probably have to post the pertinent code.  If you have NDA requirements or whatever, you can rip out all business logic and everything before you post it, as long as we can see where the methods are being called, response and other object declared, and where the events are raised.
0
 
LVL 2

Author Comment

by:Mystify
ID: 17823421
I am sure there are not 2 instances of the form, and I am sure there are not 2 instances of the class objects. I AM sure that there are 2 or more async threads however. One handling the form and the forms methods, and one handling the socket communication.

When the form loads, I add the handler of the data recieve method on the form to the socket communcation class. so when the datarecieve event fires, it's fired by an alternative thread.

Now, because the address of the method is on another thread, it IS possible that the source form is being recreated in memory and thus causing the problem. In which case, what do I do about it.

I am out of the office until monday, I will try adding the shared property to the variable and see what happens. If it works you will get full points.
0
 
LVL 2

Author Comment

by:Mystify
ID: 17842284
I can't tell if there are 2 instances of the form or objects being loaded or not, but setting to shared didn't help.
However, the behavor is that of 2 objects, so I am going to have to redesign the object layout to find a better way to do it anyway.

I am going to give points to super786 as he set me on the track that is most likely the cause of hte problem.

Thanks.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now