开发者

C# multiple threads calling single method at specific interval

I will try to make the question as simple so that it is easy to get an idea of the scenario. I am trying to build a stock related application for school project, which is fetching data from the web for a particular stock. So the user inputs stock name in a text box and after clicking the button, the name of the stock is passed to the method downloading data for that particular stock. Now i want that method to be called on every second for the same stock so that user can get the latest updates. Till now no problem. But when the user wants to monitor more than one stocks, i need to dive into threading. As for each stock there will be a thread will be calling the update stock method every second. So for example there are 5 stocks so there should be 5 threads that are working simultaneously calling the method every second to update the results. I hope i have made the problem clear to understand.

To accomplish this i am using the System.Threading.Timer in the button click event and it is calling the method for stock update. But the problem is that when i enter the first stock the method is called only 2 times, for the second stock it is being called for 6 times and for 3rd stoc开发者_JS百科k more than 12 times. What is the reason behind such weird behavior.

Any idea if there is any other way around to achieve what i am trying to do. Following is the code i am working on.

private void button1_Click(object sender, EventArgs e)
{
    dataGridView1.Rows.Add("","","","","","test", "test");
    int i= dataGridView1.Rows.Count - 1;
    string stock = textBox1.Text + ":"+i;

    System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);
}

public void Tick(object stock)
{
    lock (locker)
    {
        string maindata = stock.ToString();
        string[] testing = maindata.Split(':');
        byte[] data = null;
        Uri uri = new Uri("some url where i am getting data from");
        WebClient wc = new WebClient();

        wc.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
        {
            data = e.Result;
        };
        wc.DownloadDataAsync(uri);
        while (wc.IsBusy)
        {
            Thread.Sleep(100);
        }
        string strData = Encoding.ASCII.GetString(data);
        string[] s = strData.Split('{');
        string data1 = s[4];
        string[] data2 = data1.Split('}');
        string final = "[{" + data2[0] + "}]";

        Form1 obj = new Form1();
        List<Form1> jarray = JsonConvert.DeserializeObject<List<Form1>>(final);

        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[0].Value = jarray[0].Symbol;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[1].Value = jarray[0].Ask;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[2].Value = jarray[0].Volume;
        dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[3].Value = jarray[0].Bid;
    }      
}


Since with every click you are creating a new Timer. This will mean with every subsequent click, more timers will respond so you start getting the events twice, 4 times, ....

Move this line out of click and put it in the initialization of the form:

System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);

This does not mean I fully approve your approach since that has nothing to do with the question you are asking.


I suggest you look at Asynchronous Programming Using Delegates. On every tick (using just 1 timer) you should launch a delegate asynchronously to get your values for each stock the user requests.


"But when the user wants to monitor more than one stocks, i need to dive into threading". Not true. Now I don't want to spoil a perfectly good opportunity to dive headfirst into threading, but you don't need to here. Why not refresh all stocks at the same time?

So each time the timer ticks, you download the prices for all the stocks in one go. If you have control of the serverside interface (where you get the data from), make a method that accepts a collection of stocktickers and returns a collection of stockprices. If the server only returns one at a time, you get them on by one in a loop.

Also when you really want to have something that responds quickly, don't poll for new prices every second but have the server notify you when something has changed by subscribing to an event for instance. Some stocks will not move for minutes, while other move very quickly. For most trading purposes, a full second is a lifetime. If you're on WPF, look into DataBinding and INotifyPropertyChanged. That fits extremely well for this type of problem.

GJ


@Prashant - Obviously your approach is not correct. What you actually want to happen is to have multiple threads which will tick at different intervals. As Aliostad hinted at your approach isn't correct.

System.Threading.Timer is a simple, lightweight timer that uses callback methods and is served by thread pool threads. It is not recommended for use with Windows Forms, because its callbacks do not occur on the user interface thread. System.Windows.Forms.Timer is a better choice for use with Windows Forms. For server-based timer functionality, you might consider using System.Timers.Timer, which raises events and has additional features.

What I would do is use a mutex approach to determine if a new thread is required. I would pass the name of the stock and within the thread itself start the timer. If you wanted to a feature to "pause" or "stop" a stock from being watched would be easy enough.

The current class your using is threaded your approach itself is flawed.

As for each stock there will be a thread will be calling the update stock method every second. So for example there are 5 stocks so there should be 5 threads that are working simultaneously calling the method every second to update the results. I hope i have made the problem clear to understand.
  • Except this isn't what you are doing. What you are actualy doing is starting a new timer thread for each time the button is pressed( for every stock ) which of course is NOT what you actually want to do ( based on your own statements ).
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜