0

I need to check memory continuously for a change to notify, and I use System.Threading.Timer to achieve it. I want the notification ASAP, so I need to tun callback method quite often, and I don't want cpu to use 100% to do this.

Can anybody tell me how should I set the interval of this timer? (I think it would be good to set it minimum as possible as)

Thanks

Mehmet
  • 211
  • 1
  • 4
  • 12
  • When you say you need to check memory continuously, what exactly are you checking? Are you checking a collection, a value, an object? Furthermore, does the "memory" get modified withing your application? – Kiril Jan 16 '12 at 17:04
  • I will check a dictionary object which I will keep messages, and yes the content of dictionary will be modified quite often, since it will be used in a chat application – Mehmet Jan 16 '12 at 17:27
  • can you elaborate a little more on what will be changing in the dictionary? It's important because it will drive how you will be notified of modifications. – Kiril Jan 16 '12 at 17:36
  • Thanks for your concern. public Dictionary Messages = new Dictionary(); CometMessage will be added or removed by a web request. If a request for sending new message then CometMessage will be added, if a request for getting message then CometMessage will be removed – Mehmet Jan 16 '12 at 17:46
  • got it... ok, so I've given you a small snippet and a link to a more robust solution. – Kiril Jan 16 '12 at 17:48

1 Answers1

1

OK, so there is a very basic strategy for how you can be immediately notified of a modification to the dictionary without incurring any necessary CPU cycles and it involves using Monitor.Wait and Monitor.Pulse/Monitor.PulseAll.

On a very basic level, you have something like this:

public Dictionary<long, CometMessage> Messages = new Dictionary<long, CometMessage>();

public void ModifyDictionary(int key, CometMessage value)
{
    Messages[key] = value;
    Monitor.PulseAll(Messages);
}

public void CheckChanges()
{
    while(true)
    {
        Monitor.Wait(Messages);
        // The dictionary has changed!
        // TODO: Do some work!
    }
}

Now, this is very rudimentary and you could get all sorts of synchronization issues (read/write), so you should look into Marc Gravell's implementation of a blocking queue and apply the same logic to your dictionary (essentially making a blocking dictionary).

Furthermore, the above example will only let you know when the dictionary is modified, but it will not inform you of WHICH element was modified. It's probably better if you take the basics from above and design your system so you know which element was last modified by perhaps storing the key (e.g. last key) and just checking the value associated with it.

Community
  • 1
  • 1
Kiril
  • 39,672
  • 31
  • 167
  • 226
  • Thanks for your answer, but unfortunately I have an implementation like yours. I mean I am listening in an infinite while loop and after a while (say in 5 minutes) the CPU spikes up to 100%. So I decided to convert it into a timer way, and sure I need this timer to run with a small time interval as possible as it can – Mehmet Jan 16 '12 at 17:51
  • 1
    Please note that `Monitor.Wait` is a blocking call, so I don't see how the CPU will spike up to 100% (i.e. no CPU is utilized when you're blocking). With a `Monitor`, you will **only get an update when the `Messages` dictionary is modified**. If you do have a similar solution, then please post it so we can see the details and the potential areas where you're doing something wrong. P.S. If your solution involves a `Thread.Sleep`, then you're "doing it wrong." A timer is also the wrong way to go about this too! – Kiril Jan 16 '12 at 17:54
  • You are right, thanks a lot! So can you tell me why the timer is wrong? And I have more than thread and can I use your solution with custom threads (I mean System.Threading.Thread, not thread pool thread) ? – Mehmet Jan 16 '12 at 18:32
  • If I use ManualResetEvent rather than Monitor.Wait, would it be ok? – Mehmet Jan 16 '12 at 18:36
  • Sure, you can use a `ManualResetEvent` too. The `Timer` has the same fundamental flaw as `Thread.Sleep`: they're both polling. In general, you want to *avoid polling as much as possible* and rely on thread communication constructs (`Monitor`, `ManualResetEvent`, `Semaphore`, etc.). The concept I've outline is fully compatible with pretty much any threading model available in .NET – Kiril Jan 16 '12 at 19:05
  • Thanks again, but unfortunately I don't know how to use this mechanism. Since I need to timeout web requests even no new messages. I can't imagine this mechanism for timeout :( So If I Monitor.Wait, how can I Monitor.PulseAll without polling? – Mehmet Jan 16 '12 at 19:36
  • Mehmet, do you have the code that writes to the Messages dictionary? Whenever you're writing a message into the dictionary, then you will have to call `Monitor.PulseAll`. – Kiril Jan 16 '12 at 20:28
  • I understand that mechanism, and it works as you say. I need also an extra option: I also need to run that process even NO NEW INCOMING message. Client requests to get new messages, but NO NEW messages in 5 seconds and I have to return a response to that client. In this case writing message method is NOT called. And I don't know how to understand the timeout and return a response :( – Mehmet Jan 16 '12 at 20:39
  • If the client requests new messages, then you wouldn't use this logic. Instead, you would just go through the `Messages` dictionary and return all the messages to the client. I don't understand what's the problem you're encountering... – Kiril Jan 16 '12 at 20:45
  • I go through the Messages dictionary in an infinite while loop, and after 2-3 minutes, CPU spikes to 100%. So I converted while loop to a timer and CPU now is not spiking interestingly. So I decided to use a timer with a small interval. I don't know what is the difference between Timer and Sleep but it seems it is working. Thanks for your concern, and if you can explain the difference I would appreciate it – Mehmet Jan 16 '12 at 20:51
  • Mahmet, I don't know what your code looks like, so unless you post some code I don't know what's going on. Your explanation does not really give me any useful information which would help me provide a "better" answer. Please post a code example that depicts the problem you're seeing... – Kiril Jan 16 '12 at 21:12
  • Actually I asked my question in an other SO thread, and there is some code. And if you need to see more code I can provide to you. http://stackoverflow.com/questions/8881396/cpu-usage-increasing-up-to-100-in-infinite-loop-in-thread – Mehmet Jan 16 '12 at 21:26
  • @Mehmet I checked the other answer, but I still don't know how you schedule your threads and how often you schedule them. It may be possible that you schedule too many threads and you don't do the same thing with a timer. Running a thread in a while loop with a `Sleep(100)` alone would not cause this problem. You can even test it by making a small C# application that does only that and you will see that 100 ms is not going to peg your CPU at 100%, I don't think it will even get past 2-3%. – Kiril Jan 16 '12 at 22:26
  • I was creating 10 System.Threading.Thread, and now I am running the same code with a 5 Timers. I think you may be right, and only additional 5 threads can cause cpu to spike? If they are the same, wouldn't be better to use own threads rather than thread pool threads? – Mehmet Jan 17 '12 at 09:04
  • 1
    I'm 99% sure that this has almost nothing to do with the actual `Threading` and it's probably due to something that you're doing inside your application. As a final suggestion: it would be great if you can make an [sscce](http://sscce.org) compliant example that can easily demonstrate the problem. Otherwise, there is nothing inherently different about Timers and Threads that would result in the behavior you're describing. – Kiril Jan 17 '12 at 16:28
  • Thanks a lot Lirik for all your concern, I will recheck my implementation as you suggest – Mehmet Jan 17 '12 at 17:40