C# threading & events

A

Aidal

Hi NG.

I'm creating a little app. that has to use a 3rd party API.
The functions in this API has no return value but trigger events like OK
or NOT OK with event args.

Where I need to use this API I must have a synchrone modul so I need to
force a synchrone look to this asynchrone model of the API.

I was thinking this would call for some waiting for events and since I
don't wanna make a loop eat all the cpu power I was thinking of using a
few threads to accomplish this.

It's giving me some trouble though I'm aware it's a pretty common and
simple scenario.

I was hoping maybe somone here could lend me a hand.

What I need is as said, to make some code that uses the API but my code
has to be synchrone while the API is not.

So I can do somthing like:
--------------------------
public MyClass
{
private bool InProcess;
private bool ItWentWell;

public bool Function1()
{
InProcess = true;

APIClass apic = new APIClass();

apic.FunctionAPI1_Success += EventHandler(FunctionOK);
apic.FunctionAPI1_Failed += EventHandler(FunctionERROR);

apic.FunctionAPI1();

...
Wait for InProcess to change from TRUE to FALSE.
Once this happens, return ItWentWell.
}

public void FunctionOK()
{
Inprocess = false;

ItWentWell = true;
}

public void FunctionERROR()
{
InProcess = false;

ItWentWell = false;
}
}

//--- somwhere like the Main of a console app. ---
MyClass mc = new MyClass();

if(mc.Function1())
{
Consile.WriteLine("API call went well.");
}
else
{
Consile.WriteLine("API call went bad.")
}
--------------------------

I'm aware that the above doesn't work, it's only to give a picture of
what I'm trying to accomplish. Somwhere around the part with the waiting
for the event to occur should most likely be using a new thread not to
eat all the cpu power, but I can't get the things I've tried to work.

Any help would be much appreciated, thanks :)

/Aidal
 
B

Ben Voigt

Aidal said:
Hi NG.

I'm creating a little app. that has to use a 3rd party API.
The functions in this API has no return value but trigger events like OK
or NOT OK with event args.

Where I need to use this API I must have a synchrone modul so I need to
force a synchrone look to this asynchrone model of the API.

I was thinking this would call for some waiting for events and since I
don't wanna make a loop eat all the cpu power I was thinking of using a
few threads to accomplish this.

Use the EventWaitHandle class built in to .NET. Or convert your algorithm
to a state machine.
 
A

Aidal

Aidal skrev:
Hi NG.

I'm creating a little app. that has to use a 3rd party API.
The functions in this API has no return value but trigger events like OK
or NOT OK with event args.

Where I need to use this API I must have a synchrone modul so I need to
force a synchrone look to this asynchrone model of the API.

I was thinking this would call for some waiting for events and since I
don't wanna make a loop eat all the cpu power I was thinking of using a
few threads to accomplish this.

It's giving me some trouble though I'm aware it's a pretty common and
simple scenario.

I was hoping maybe somone here could lend me a hand.

What I need is as said, to make some code that uses the API but my code
has to be synchrone while the API is not.

So I can do somthing like:
--------------------------
public MyClass
{
private bool InProcess;
private bool ItWentWell;

public bool Function1()
{
InProcess = true;

APIClass apic = new APIClass();

apic.FunctionAPI1_Success += EventHandler(FunctionOK);
apic.FunctionAPI1_Failed += EventHandler(FunctionERROR);

apic.FunctionAPI1();

...
Wait for InProcess to change from TRUE to FALSE.
Once this happens, return ItWentWell.
}

public void FunctionOK()
{
Inprocess = false;

ItWentWell = true;
}

public void FunctionERROR()
{
InProcess = false;

ItWentWell = false;
}
}

//--- somwhere like the Main of a console app. ---
MyClass mc = new MyClass();

if(mc.Function1())
{
Consile.WriteLine("API call went well.");
}
else
{
Consile.WriteLine("API call went bad.")
}
--------------------------

I'm aware that the above doesn't work, it's only to give a picture of
what I'm trying to accomplish. Somwhere around the part with the waiting
for the event to occur should most likely be using a new thread not to
eat all the cpu power, but I can't get the things I've tried to work.

Any help would be much appreciated, thanks :)

/Aidal

Anyone have an actual code example or a link to one where:

Class1.FunctionA calls Class2.FunctionB which will (at some point)
trigger an event.
Class1.FunctionA must not return before the event occuers because it
needs to base its return value on what the event "said" like true/false.

Aka Class1.FunctionA must wait for the event triggered by
Class2.FunctionB to occuer before it knows what to return.

As mentioned above I assume some threading should be used but I'm not sure.

/Aidal
 
M

Marc Gravell

Like so?

using System;
using System.Threading;

static class Program
{
static void Main()
{
new ClassA().MethodA();
}
}
class ClassA
{
public void MethodA()
{
ClassB b = new ClassB();
string theSomething = "";
ManualResetEvent evt = new ManualResetEvent(false);
b.SomethingHappened += delegate
{
theSomething = b.TheSomething;
evt.Set();
};
ThreadPool.QueueUserWorkItem(delegate {
b.MethodB();
});
evt.WaitOne();
Console.WriteLine(theSomething);
}
}
class ClassB
{
public event EventHandler SomethingHappened;
private string _theSomething;
public string TheSomething {get {return _theSomething;}}
protected void OnSomethingHappened()
{
EventHandler handler = SomethingHappened;
if (handler != null) handler(this, EventArgs.Empty);
}
public void MethodB()
{
_theSomething = Console.ReadLine();
OnSomethingHappened();
}
}
 
M

Marc Gravell

Note: for brevity, in my example I didn't bother putting the "what
happened" into an event-arg subclass - but this would work identically
to the property approach; you may also wish to be "using" the
ManualResetEvent (since it is IDisposable).

As an alternative, note that you can also do this using locks to avoid
the (marginally more expensive) ManualResetEvent - but unless you are
high volume it might not be worth it; note to follow the logic here
requires a good understanding of "lock" (Monitor.Enter, Monitor.Exit),
Monitor.Wait and Monitor.Pulse...

public void MethodA() {
ClassB b = new ClassB();
string theSomething = "";
object sync = new object();
b.SomethingHappened += delegate {
theSomething = b.TheSomething;
lock (sync) {
Monitor.Pulse(sync);
}
};
lock (sync) {
ThreadPool.QueueUserWorkItem(delegate {
b.MethodB();
});
Monitor.Wait(sync);
}
Console.WriteLine(theSomething);
}
 
A

Aidal

Marc Gravell skrev:
Like so?

using System;
using System.Threading;

static class Program
{
static void Main()
{
new ClassA().MethodA();
}
}
class ClassA
{
public void MethodA()
{
ClassB b = new ClassB();
string theSomething = "";
ManualResetEvent evt = new ManualResetEvent(false);
b.SomethingHappened += delegate
{
theSomething = b.TheSomething;
evt.Set();
};
ThreadPool.QueueUserWorkItem(delegate {
b.MethodB();
});
evt.WaitOne();
Console.WriteLine(theSomething);
}
}
class ClassB
{
public event EventHandler SomethingHappened;
private string _theSomething;
public string TheSomething {get {return _theSomething;}}
protected void OnSomethingHappened()
{
EventHandler handler = SomethingHappened;
if (handler != null) handler(this, EventArgs.Empty);
}
public void MethodB()
{
_theSomething = Console.ReadLine();
OnSomethingHappened();
}
}

I've tried to create your example but it appears to have syntax errors
around "b.SomthingHappened += delegate". :(

/Aidal
 
A

Aidal

Marc Gravell skrev:
Like so?

using System;
using System.Threading;

static class Program
{
static void Main()
{
new ClassA().MethodA();
}
}
class ClassA
{
public void MethodA()
{
ClassB b = new ClassB();
string theSomething = "";
ManualResetEvent evt = new ManualResetEvent(false);
b.SomethingHappened += delegate
{
theSomething = b.TheSomething;
evt.Set();
};
ThreadPool.QueueUserWorkItem(delegate {
b.MethodB();
});
evt.WaitOne();
Console.WriteLine(theSomething);
}
}
class ClassB
{
public event EventHandler SomethingHappened;
private string _theSomething;
public string TheSomething {get {return _theSomething;}}
protected void OnSomethingHappened()
{
EventHandler handler = SomethingHappened;
if (handler != null) handler(this, EventArgs.Empty);
}
public void MethodB()
{
_theSomething = Console.ReadLine();
OnSomethingHappened();
}
}

The actual scenario is:
=======================
ClassAPI has a function
- void SendFile()
and the two events
- FileSendOK
and
- FileSendError

MyClass has the function
- bool SendFile()
which is to use the function ClassAPI.SendFile()

What I want to be able to do is:
--------------------------------
MyClass mc = new MyClass();

if(mc.SendFile())
{
do somthing when sending file is successful...
}
else
{
do somthing else when sending file fails...
}
---------------------------------

Which means MyClass.SendFile() must wait for one of the two events in
ClassAPI to occuer (due to the ClassAPI.SendFile call) before it returns.

/Aidal
 
M

Marc Gravell

Ah... 1.1... I was heavily using the "captured variable" feature of
anonymous methods as a means to share state between threads. Never
mind... it can be done the other way - it just takes more code. Note:
I hanve't tested this in 1.1, so it may need tweaking, but it should
be fairly close (may also need to lose "static" from "static class
Program"):

class ClassA
{
internal class MethodAState
{
private readonly ClassB B;
private readonly object Sync = new object();
private string _theSomething;
public MethodAState()
{
B = new ClassB();
B.SomethingHappened += new
EventHandler(B_SomethingHappened);
}
public string StartAndWaitMethodB()
{
lock (Sync)
{
ThreadPool.QueueUserWorkItem(new
WaitCallback(B_StartB));
Monitor.Wait(Sync);
return _theSomething;
}
}
void B_StartB(object state)
{
B.MethodB();
}

void B_SomethingHappened(object sender, EventArgs e)
{
lock (Sync)
{
_theSomething = B.TheSomething;
Monitor.Pulse(Sync);
}
}

}
public void MethodA()
{
MethodAState state = new MethodAState();
string value = state.StartAndWaitMethodB();
Console.WriteLine(value);
}
}
 
M

Marc Gravell

Previous post re-worked to handle two different events with differing
signatures (pretend that TheSomething is in the event-args <g>). Type
"boom" to get the new behaviour; the string could likewise be a
success bool:

using System;
using System.Threading;

class Program
{
static void Main()
{
new ClassA().MethodA();
}
}
class ClassA
{
internal class MethodAState
{
private readonly ClassB B;
private readonly object Sync = new object();
private string _theSomething;
public MethodAState()
{
B = new ClassB();
B.SomethingHappened += new
EventHandler(B_SomethingHappened);
B.SomethingElseHappened +=new
EventHandler(B_SomethingElseHappened);
}
public string StartAndWaitMethodB()
{
lock (Sync)
{
ThreadPool.QueueUserWorkItem(new
WaitCallback(B_StartB));
Monitor.Wait(Sync);
return _theSomething;
}
}
void B_StartB(object state)
{
B.MethodB();
}

void B_SomethingHappened(object sender, EventArgs e)
{
ReleaseCaller(B.TheSomething);
}
void B_SomethingElseHappened(object sender, EventArgs e)
{
ReleaseCaller("PANIC PANIC PANIC");
}
private void ReleaseCaller(string result)
{
lock (Sync)
{
_theSomething = result;
Monitor.Pulse(Sync);
}
}

}
public void MethodA()
{
MethodAState state = new MethodAState();
string value = state.StartAndWaitMethodB();
Console.WriteLine(value);
}
}
class ClassB
{
public event EventHandler SomethingHappened,
SomethingElseHappened;
private string _theSomething;
public string TheSomething { get { return _theSomething; } }
private void OnEvent(EventHandler handler)
{
if (handler != null) handler(this, EventArgs.Empty);
}
public void MethodB()
{
string value = Console.ReadLine();
if (value == "boom")
{
OnEvent(SomethingElseHappened);
}
else
{
_theSomething = value;
OnEvent(SomethingHappened);
}
}
}
 
A

Aidal

Marc Gravell skrev:
Previous post re-worked to handle two different events with differing
signatures (pretend that TheSomething is in the event-args <g>). Type
"boom" to get the new behaviour; the string could likewise be a
success bool:

using System;
using System.Threading;

class Program
{
static void Main()
{
new ClassA().MethodA();
}
}
class ClassA
{
internal class MethodAState
{
private readonly ClassB B;
private readonly object Sync = new object();
private string _theSomething;
public MethodAState()
{
B = new ClassB();
B.SomethingHappened += new
EventHandler(B_SomethingHappened);
B.SomethingElseHappened +=new
EventHandler(B_SomethingElseHappened);
}
public string StartAndWaitMethodB()
{
lock (Sync)
{
ThreadPool.QueueUserWorkItem(new
WaitCallback(B_StartB));
Monitor.Wait(Sync);
return _theSomething;
}
}
void B_StartB(object state)
{
B.MethodB();
}

void B_SomethingHappened(object sender, EventArgs e)
{
ReleaseCaller(B.TheSomething);
}
void B_SomethingElseHappened(object sender, EventArgs e)
{
ReleaseCaller("PANIC PANIC PANIC");
}
private void ReleaseCaller(string result)
{
lock (Sync)
{
_theSomething = result;
Monitor.Pulse(Sync);
}
}

}
public void MethodA()
{
MethodAState state = new MethodAState();
string value = state.StartAndWaitMethodB();
Console.WriteLine(value);
}
}
class ClassB
{
public event EventHandler SomethingHappened,
SomethingElseHappened;
private string _theSomething;
public string TheSomething { get { return _theSomething; } }
private void OnEvent(EventHandler handler)
{
if (handler != null) handler(this, EventArgs.Empty);
}
public void MethodB()
{
string value = Console.ReadLine();
if (value == "boom")
{
OnEvent(SomethingElseHappened);
}
else
{
_theSomething = value;
OnEvent(SomethingHappened);
}
}
}
Thanks Marc :)

This example looks very interesting, I will try to apply the idea to my
code as soon as I get a free moment from other stuff.

/Aidal
 
A

Aidal

Aidal skrev:
Marc Gravell skrev:
Thanks Marc :)

This example looks very interesting, I will try to apply the idea to my
code as soon as I get a free moment from other stuff.

/Aidal

By the way, do the internal MethodState class have to be internal or
could it just as well be a public class next to ClassA and ClassB ?

/Aidal
 
M

Marc Gravell

It perfectly well could be, but the only reason for its existance is
to manage the state during a threaded method invoke. There is no
reason for this to be public, as nothing outside should care about it;
equally, this is one of the (rare) cases where (IMO) a nested class
helps to clarify the class scope. If multiple methods in the same
assembly have similar scope requirements then I guess I might elevate
it to a namespace-level class, and *perhaps* make it public if it is
common across assemblies. But nested and internal was my instinct for
this.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top