-2

First of all, I am creating new thread because I want to get the cursor location to be displayed on the form. So, here's what I did, inside the class, I created a thread and using that thread I am running that method which will assign cursor location to labels on my form.

public partial class Main : Form
{
    public Main()
    {
        InitializeComponent();
        CheckForIllegalCrossThreadCalls = false;
    }

    private void GetCurLoc()
    {
        while (true)
        {
            PosX.Text = MousePosition.X.ToString();
            PosY.Text = (Int32.Parse(PosYMax.Text) - MousePosition.Y).ToString();
        }
    }

    private void Main_Load(object sender, EventArgs e)
    {
        Thread curLoc = new Thread(new ThreadStart(GetCurLoc));
        curLoc.Start();
    }
}

But, the application consumes so much CPU and power. Why one thread will consume such CPU? To me, it seems my thread creation is doing a resource leak.

Please help.

Hasan
  • 247
  • 7
  • 22
  • 1
    It's not resource leak. What do you think while(true) is doing? It doesn't wait for anything or even check if the cursor changed, but instead immediately run the loop again – Martheen Oct 26 '20 at 07:17
  • Yes, because I need to constantly check the locations as the cursor moves. – Hasan Oct 26 '20 at 07:17
  • No you don't need to. – quetzalcoatl Oct 26 '20 at 07:18
  • If you need to know the position of the Mouse Pointer anywhere in the current Desktop, not just your application, use a Timer (~100ms). If you need to know the position of the Pointer inside a specific control's bounds, just handle the MouseMove event. – Jimi Oct 26 '20 at 13:31
  • Please note that `CheckForIllegalCrossThreadCalls` is specifically documented as a **debugging** mechanism. If you're intending to use it in production code then you are going to cause yourself grief. https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.checkforillegalcrossthreadcalls?view=netcore-3.1 – Enigmativity Oct 26 '20 at 23:02
  • @Enigmativity, yes, that is not how it looks in production. – Hasan Oct 27 '20 at 08:29
  • @Hasan - How does it look in production? – Enigmativity Oct 27 '20 at 09:34
  • @Enigmativity, like this https://stackoverflow.com/a/46789543/7660998 – Hasan Oct 28 '20 at 15:10

2 Answers2

5

while(true) spins as fast as it can, and here comes your 100% CPU usage.

Add some delays. Yeah, sounds bad, but if you really want a while(true) then either it must spin at 100% cpu for some business reason of yours, or you may slow it down to some acceptable level of "often". If that's UI code, probably adding a 25-100ms delay between iterations will be fine.

Or, get rid of the loop completely. It seems that this loop inspects mouse position and stores it somewhere. Use mouse events to be notified when mouse position changes and act only when such event arrives, instead instead of busy-looping and blindly checking "are we there yet?" all the time.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
  • (I was going to comment on your answer on [Why does cmov always return t\_val?](https://stackoverflow.com/q/64532771), but you deleted it so I left an edit instead to explain in more detail why that guess isn't right, and how you could test such guesses more reliably. Thought you might be interested and wasn't sure if SO would ping you about the edit.) – Peter Cordes Oct 26 '20 at 07:45
  • @PeterCordes: Indeed SO didn't ping me, but your comment here did. Yes, I've deleted my answer because something felt odd (`test` may has versions with shorter-length operands and the compiler knows that `pred` is shorter, etc) and after rechecking on the original code - my "fix" turned out to be totally missed. And your response made so much more sense, including the fact I didn't know about early-clobbers flag :) Thank you! I'll definitely re-read your answer. – quetzalcoatl Oct 26 '20 at 11:19
  • @PeterCordes OOoohh you've edited my deleted answer, OK, I see what you meant. Actually, SO pinged me about that too, just the notification message was pretty uninspiring - "code edited on answer xxx" - and I'd probably skip it if you didn't drop me a note here. Thanks again. – quetzalcoatl Oct 26 '20 at 11:21
  • 1
    (edit: apparently this is redundant, you hadn't seen my edit to your answer before that earlier comment). All simple instructions that date back to 8086 are available with any operand size, not just `test`. And yes, GCC will *definitely* pick an 8-bit register for an 8-bit variable, that's how GNU C inline asm works. To get it to emit `test %eax,%eax`, you'd have to write `test %k1, %k1` to override to the 32-bit version of the register name, instead of whatever the compiler picked. https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#x86-Operand-Modifiers – Peter Cordes Oct 26 '20 at 11:23
2

What you're wanting to do here is really respond to the MouseMove event for every control on your form. That's easy with Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive.Windows.Forms and add using System.Reactive.Linq; - then you can do this:

    private IDisposable _subscription = null;

    private void Form1_Load(object sender, EventArgs e)
    {
        IEnumerable<Control> GetAllControls(Control control)
        {
            yield return control;
            foreach (var c1 in control.Controls.Cast<Control>())
                foreach (var c2 in GetAllControls(c1))
                    yield return c2;
        }

        _subscription =
            GetAllControls(this)
                .ToObservable()
                .SelectMany(c =>
                    Observable
                        .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                            h => c.MouseMove += h, h => c.MouseMove -= h))
                .ObserveOn(this)
                .Select(_ => new
                {
                    X = MousePosition.X.ToString(),
                    Y = (Int32.Parse(PosYMax.Text) - MousePosition.Y).ToString()
                })
                .Subscribe(z =>
                {
                    PosX.Text = z.X;
                    PosY.Text = z.Y;
                });
    }

That automatically attaches to every control's MouseMove event and then aggregates all of the events into a single observable which computes the X and Y values that you want.

There is no need for threads or timers.

Just call _subscription.Dispose() to detach from all of the event handlers.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • I see. Its true that I could not think how could I get mouse events of the outside of my form. I will surely take a look on this. – Hasan Oct 27 '20 at 08:32
  • 1
    @Hasan - This only works for the mouse events on your form. It wouldn't be hard to incorporate a timer in this query (i.e. `Observable.Interval(TimeSpan.FromSeconds(0.1))`) to poll the coordinates from outside the form. – Enigmativity Oct 27 '20 at 09:33
  • I get it, but I unfortunately, I had not worked on the project after that, I will let you know if I have any update. RN, its done with Task.Delay, bit expensive, I know, but does the work for now. – Hasan Oct 28 '20 at 15:12