It is currently December 3rd, 2020, 10:45 am

[help] C# and multithreading

Share and get help with Plugins and Addons
FlyingHyrax
Posts: 251
Joined: July 1st, 2011, 1:32 am
Location: US

[help] C# and multithreading

Post by FlyingHyrax »

(The particular original question of this thread is no longer quite relevant.)
So I'm working on a plugin. The idea is that the plugin can run a command, and will return the output of the command as a string (rather like the 'exec' variable in Conky).

C# has a really handy little class called Process that is stunningly perfect for this and works swimmingly. (C# is also perfect because I don't know enough C++ to break an egg. I know I'll have to learn it eventually because everyone everywhere uses it, but I really hate it and would rather spend my free time learning, say, Go. But I digress.)

Anyway. Yesterday I got a little prototype working, and it was kind of exciting, except for the part where the plugin had to wait for the process to complete before returning the output. So if you ran, say, tracert, Rainmeter would hang for as long as it took to run tracert <ip>, which is rather undesirable behavior.

After some thought, it occurred to me that if the process was started by another thread, that thread could sit and wait for it to finish while the main thread kept chugging, thus keeping Rainmeter responsive. So I started to read some online about multi-threading, and my head exploded. I've managed to get to the point where I can spawn a new thread that starts the process and waits on it, and I've also got the process writing asynchronously to a StringBuilder that I can return in GetString() from the main thread (again, that Process class is a real hero). You can see what I have so far on GitHub.

The trick now is, um, stopping the thread.

This problem can be delightfully well-illustrated by running tracert through the plugin, then refreshing the skin a few times. Every refresh spawns a new thread, each thread is doing it's thing, and all of them are writing intermittently to the output string.

As such, can anyone with some multithreading experience point me to some mechanisms or a flow of control that might work here? In the end, I'd like to have the plugin run the command once on refresh (but then there's DynamicVariables. Yikes), or on demand using !CommandMeasure. The process has to be started by its own thread to keep Rainmeter from hanging, but there should only be one process thread at a time. Anyone have any suggestions on how to accomplish this? Any particular online reading I should be doing? (I've been slogging through this, and it's been very helpful, but golly is it a LOT.) I'm just really new to this, so any way to narrow down my thinking will help.

If you made it this far, thanks for reading and thanks in advance for any suggestions.

Postscript: Not distributing binaries yet since it's so rough, but if you want to build it yourself from the source on GitHub to play around with it, this is the skin I've been using to test:

Code: Select all

[Rainmeter]
DynamicWindowSize=1

[Metadata]
Name=ExecTest
Author=Flying Hyrax | flyinghyrax.deviantart.com
Information=test skin for a plugin that aims to replicate the "exec" variable from conky. | Given a command and arguments, will run the command and return the console output as a string
Version=beta
License=CC BY-NC-SA 4.0

[Variables]
prog="tracert"
args="www.bbc.co.uk"

[mExec]
Measure=Plugin
Plugin="Exec.dll"
ExecFile=#prog#
Arguments=#args#
;WriteToFile="#CURRENTPATH#\output.txt"
;UpdateDivider=-1

[header]
Meter=String
X=0
Y=0
SolidColor=0,0,0,200
FontFace=Segoe UI
FontSize=12
FontColor=100,250,100
AntiAlias=1
Text="ExecTest #prog# #args#"

[string]
Meter=String
MeasureName=mExec
X=r
Y=R
SolidColor=0,0,0,200
FontFace=Lucida Console
FontSize=10
FontColor=250,250,250
AntiAlias=1
Text=%1
Last edited by FlyingHyrax on December 20th, 2013, 3:27 am, edited 2 times in total.
Flying Hyrax on DeviantArt
User avatar
Aragas
Posts: 64
Joined: December 24th, 2012, 6:56 pm
Location: Russia, Moscow

Re: [plzhelp] C# and multithreading

Post by Aragas »

First, better make
private Thread procThread;
I just compiled it and have run with your Rainmeter skin. Trace works, no freezings detected
UPD:
You have a 1-core processor?
UPD2:
Maybe eating resources is caused by not checking it procThread is already running. I make some fixes in fork.
UPD3:
multithreading is very evil. Your thread will work even if you close skin. You need monitor if skin is closed.
I'm not good in english, as you can see, and, maybe my code will be unreadable for you. But i recommend to see my plugin for RM https://github.com/Aragas/VKPlugin_V2. I'm using multhithreading there too, check Player.cs in AudioPlayer. :D
FlyingHyrax
Posts: 251
Joined: July 1st, 2011, 1:32 am
Location: US

Re: [plzhelp] C# and multithreading

Post by FlyingHyrax »

As it is currently, it won't hang Rainmeter, but if you refresh the test skin a few times, you get interleaved output from multiple threads each running a process (because my call to to SpawnProcThread() is in Measure.Reload()).

1) I have an i3. 2 physical cores, each with 2 virtual cores.
2) I wasn't sure how to do that; the Thread object has state properties, but the state can change between when you check it and when you act on it.

3) I agree. I need to implement Measure.Cleanup(); if I can learn to keep track of the extra thread so there will only ever be one, then it would be trivial to make sure it is terminated.

I'll have a look at your code; thank you for your feedback! :)
Last edited by FlyingHyrax on December 19th, 2013, 6:10 pm, edited 1 time in total.
Flying Hyrax on DeviantArt
User avatar
Aragas
Posts: 64
Joined: December 24th, 2012, 6:56 pm
Location: Russia, Moscow

Re: [plzhelp] C# and multithreading

Post by Aragas »

Just have fixed problem with multiple threads. Don't forget to check if thread is already running. See my fork
Last edited by Aragas on December 19th, 2013, 6:20 pm, edited 2 times in total.
FlyingHyrax
Posts: 251
Joined: July 1st, 2011, 1:32 am
Location: US

Re: [plzhelp] C# and multithreading

Post by FlyingHyrax »

Thank you! I'll add that in.

I'm very new to C#, but I'll study your VKPlugin code. Should be helpful. Thanks!
Flying Hyrax on DeviantArt
User avatar
Aragas
Posts: 64
Joined: December 24th, 2012, 6:56 pm
Location: Russia, Moscow

Re: [plzhelp] C# and multithreading

Post by Aragas »

Happy to help. Would be cool if we would have more C# plugins. I'm not a pro in C#, but i think i now good how C# work in Rainmeter, so ask me anytime if you have troubles.
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [plzhelp] C# and multithreading

Post by jsmorley »

Aragas wrote:Happy to help. Would be cool if we would have more C# plugins. I'm not a pro in C#, but i think i now good how C# work in Rainmeter, so ask me anytime if you have troubles.
Aragas,

Officially hijacking this thread... ;-)

I have a little C# plugin that I would like to "thread" as well. I am very new to C#, and entirely unfamiliar with threads in C#, so I wonder if you might point me in the right direction as well.

The code is at:

https://github.com/jsmorley/CheckNet

And should be used in the context of the Rainmeter Plugin SDK at:

https://github.com/rainmeter/rainmeter-plugin-sdk.

A sample skin is at:

http://rainmeter.net/forum/viewtopic.php?p=93547#p93547

What I would like to do is have the "network" and "internet" checking done in a thread, so if the "internet" (the DNS resolution bit) is slow, Rainmeter is not "blocked" while waiting for it to finish.

I don't think there should ever be a reason to spawn a second thread, so I'm not sure that CRITICAL_SECTION or Mutex should be an issue. I think any second execution while a thread is already running should probably just not run. I suppose there should be some kind of timeout included in the process, so if for some reason (and I'm not sure it is entirely possible) a thread to the "network" check never ends as either success or failure, it can be told to terminate and return "-1" after some number of milliseconds.

If you have some ideas about how this would be implemented in code like mine, that would be a great help. At some point I would like to add a simple example of using threading in C# in the SDK in any case.
User avatar
jsmorley
Developer
Posts: 21520
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: [plzhelp] C# and multithreading

Post by jsmorley »

Perhaps the easiest way to ensure that only one instance of the thread is running at a time is to move the increment of UpdateCounter inside the thread, so the plugin just ignores any second call to it when a thread is active. Not sure. We would need to take into consideration someone closing the skin or "refreshing" it while the thread is active I suppose.
User avatar
Aragas
Posts: 64
Joined: December 24th, 2012, 6:56 pm
Location: Russia, Moscow

Re: [plzhelp] C# and multithreading

Post by Aragas »

Seems interesting. Yes, multithreading sample must include check if skin is unload. I'll put it in my fork.
FlyingHyrax
Posts: 251
Joined: July 1st, 2011, 1:32 am
Location: US

Re: [plzhelp] C# and multithreading

Post by FlyingHyrax »

jsmorley wrote: Aragas,

Officially hijacking this thread... ;-)
My fault for naming the thread "C# and multithreading". Tad bit too broad. ;)
Flying Hyrax on DeviantArt