Threadsafe oneshot-event which fires on subscription if the event was fired in the past
up vote
7
down vote
favorite
Assumptions
Basically, a Connection class has a "Disconnect" event. Subscribing to this event isn't thread-safe, because the disconnection may fire from another thread right before I subscribe. So checking before the subscription doesn't help.
Checking for the disconnect after subscription doesn't help either because the event may have fired in the meanwhile (2 threads might execute the same "observer" twice).
(My) Solution:
An event always fired once (and only once), even if the event itself already happened before Source is on GitHub as well.
Questions:
Are there other simpler solutions addressing this? (by simpler I mean from an outside or usage perspective)
Do you see any race conditions or things that could go wrong?
Maybe you have optimizations or simplifications to add?
Input is highly appreciated!
/// <summary>
/// Triggers if the event is invoked or was invoked before subscribing to it.
/// <para> Can be accessed safely by multiple threads.</para>
/// </summary>
public class AutoInvokeEvent<Sender, Args>
{
public delegate void EventHandle(Sender sender, Args arguments);
/// <summary>
/// Handle will be invoked if the event was triggered in the past.
/// <para>Unsubscribing happens automatically after the invocation and is redundant if done from the event handle.</para>
/// </summary>
public event EventHandle Event
{
add
{
if (!Subscribe(value))
value(m_sender, m_eventArgs);
}
remove { InternalEvent -= value; }
}
private event EventHandle InternalEvent;
// this is my personal lock implementation. in this case it is used like any other lock(object) so just ignore it
private SafeExecutor m_lock = new SingleThreadExecutor();
private volatile bool m_invoked = false;
Sender m_sender;
Args m_eventArgs;
/// <summary>
/// Invokes all subscribed handles with the given parameters.
/// <para>All calls after the first are ignored.</para>
/// </summary>
public void Invoke(Sender sender, Args args)
{
GetEventHandle(sender, args)?.Invoke(m_sender, m_eventArgs);
}
private EventHandle GetEventHandle(Sender sender, Args args)
{
return m_lock.Execute(() =>
{
if (m_invoked)
return null;
m_sender = sender;
m_eventArgs = args;
m_invoked = true;
EventHandle handle = InternalEvent;
InternalEvent = null;
return handle;
});
}
/// <returns>Returns true if subscription was successful and false if handle needs to be invoked immediately.</returns>
private bool Subscribe(EventHandle handle)
{
return m_lock.Execute(() =>
{
if (!m_invoked)
InternalEvent += handle;
return !m_invoked;
});
}
}
How the class could be used :
class Connection
{
public AutoInvokeEvent<object, EndPoint> OnDisconnect = new AutoInvokeEvent<object, EndPoint>();
public Disconnect()
{
OnDisconnect.Invoke(this, endpoint);
}
}
void main()
{
Connection connection = new Connection();
connection.OnDisconnect.Event += DoStuffOnDisconnect;
}
void DoStuffOnDisconnect(object sender, EndPoint endpoint) { }
c# multithreading thread-safety event-handling observer-pattern
New contributor
add a comment |
up vote
7
down vote
favorite
Assumptions
Basically, a Connection class has a "Disconnect" event. Subscribing to this event isn't thread-safe, because the disconnection may fire from another thread right before I subscribe. So checking before the subscription doesn't help.
Checking for the disconnect after subscription doesn't help either because the event may have fired in the meanwhile (2 threads might execute the same "observer" twice).
(My) Solution:
An event always fired once (and only once), even if the event itself already happened before Source is on GitHub as well.
Questions:
Are there other simpler solutions addressing this? (by simpler I mean from an outside or usage perspective)
Do you see any race conditions or things that could go wrong?
Maybe you have optimizations or simplifications to add?
Input is highly appreciated!
/// <summary>
/// Triggers if the event is invoked or was invoked before subscribing to it.
/// <para> Can be accessed safely by multiple threads.</para>
/// </summary>
public class AutoInvokeEvent<Sender, Args>
{
public delegate void EventHandle(Sender sender, Args arguments);
/// <summary>
/// Handle will be invoked if the event was triggered in the past.
/// <para>Unsubscribing happens automatically after the invocation and is redundant if done from the event handle.</para>
/// </summary>
public event EventHandle Event
{
add
{
if (!Subscribe(value))
value(m_sender, m_eventArgs);
}
remove { InternalEvent -= value; }
}
private event EventHandle InternalEvent;
// this is my personal lock implementation. in this case it is used like any other lock(object) so just ignore it
private SafeExecutor m_lock = new SingleThreadExecutor();
private volatile bool m_invoked = false;
Sender m_sender;
Args m_eventArgs;
/// <summary>
/// Invokes all subscribed handles with the given parameters.
/// <para>All calls after the first are ignored.</para>
/// </summary>
public void Invoke(Sender sender, Args args)
{
GetEventHandle(sender, args)?.Invoke(m_sender, m_eventArgs);
}
private EventHandle GetEventHandle(Sender sender, Args args)
{
return m_lock.Execute(() =>
{
if (m_invoked)
return null;
m_sender = sender;
m_eventArgs = args;
m_invoked = true;
EventHandle handle = InternalEvent;
InternalEvent = null;
return handle;
});
}
/// <returns>Returns true if subscription was successful and false if handle needs to be invoked immediately.</returns>
private bool Subscribe(EventHandle handle)
{
return m_lock.Execute(() =>
{
if (!m_invoked)
InternalEvent += handle;
return !m_invoked;
});
}
}
How the class could be used :
class Connection
{
public AutoInvokeEvent<object, EndPoint> OnDisconnect = new AutoInvokeEvent<object, EndPoint>();
public Disconnect()
{
OnDisconnect.Invoke(this, endpoint);
}
}
void main()
{
Connection connection = new Connection();
connection.OnDisconnect.Event += DoStuffOnDisconnect;
}
void DoStuffOnDisconnect(object sender, EndPoint endpoint) { }
c# multithreading thread-safety event-handling observer-pattern
New contributor
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
1
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday
add a comment |
up vote
7
down vote
favorite
up vote
7
down vote
favorite
Assumptions
Basically, a Connection class has a "Disconnect" event. Subscribing to this event isn't thread-safe, because the disconnection may fire from another thread right before I subscribe. So checking before the subscription doesn't help.
Checking for the disconnect after subscription doesn't help either because the event may have fired in the meanwhile (2 threads might execute the same "observer" twice).
(My) Solution:
An event always fired once (and only once), even if the event itself already happened before Source is on GitHub as well.
Questions:
Are there other simpler solutions addressing this? (by simpler I mean from an outside or usage perspective)
Do you see any race conditions or things that could go wrong?
Maybe you have optimizations or simplifications to add?
Input is highly appreciated!
/// <summary>
/// Triggers if the event is invoked or was invoked before subscribing to it.
/// <para> Can be accessed safely by multiple threads.</para>
/// </summary>
public class AutoInvokeEvent<Sender, Args>
{
public delegate void EventHandle(Sender sender, Args arguments);
/// <summary>
/// Handle will be invoked if the event was triggered in the past.
/// <para>Unsubscribing happens automatically after the invocation and is redundant if done from the event handle.</para>
/// </summary>
public event EventHandle Event
{
add
{
if (!Subscribe(value))
value(m_sender, m_eventArgs);
}
remove { InternalEvent -= value; }
}
private event EventHandle InternalEvent;
// this is my personal lock implementation. in this case it is used like any other lock(object) so just ignore it
private SafeExecutor m_lock = new SingleThreadExecutor();
private volatile bool m_invoked = false;
Sender m_sender;
Args m_eventArgs;
/// <summary>
/// Invokes all subscribed handles with the given parameters.
/// <para>All calls after the first are ignored.</para>
/// </summary>
public void Invoke(Sender sender, Args args)
{
GetEventHandle(sender, args)?.Invoke(m_sender, m_eventArgs);
}
private EventHandle GetEventHandle(Sender sender, Args args)
{
return m_lock.Execute(() =>
{
if (m_invoked)
return null;
m_sender = sender;
m_eventArgs = args;
m_invoked = true;
EventHandle handle = InternalEvent;
InternalEvent = null;
return handle;
});
}
/// <returns>Returns true if subscription was successful and false if handle needs to be invoked immediately.</returns>
private bool Subscribe(EventHandle handle)
{
return m_lock.Execute(() =>
{
if (!m_invoked)
InternalEvent += handle;
return !m_invoked;
});
}
}
How the class could be used :
class Connection
{
public AutoInvokeEvent<object, EndPoint> OnDisconnect = new AutoInvokeEvent<object, EndPoint>();
public Disconnect()
{
OnDisconnect.Invoke(this, endpoint);
}
}
void main()
{
Connection connection = new Connection();
connection.OnDisconnect.Event += DoStuffOnDisconnect;
}
void DoStuffOnDisconnect(object sender, EndPoint endpoint) { }
c# multithreading thread-safety event-handling observer-pattern
New contributor
Assumptions
Basically, a Connection class has a "Disconnect" event. Subscribing to this event isn't thread-safe, because the disconnection may fire from another thread right before I subscribe. So checking before the subscription doesn't help.
Checking for the disconnect after subscription doesn't help either because the event may have fired in the meanwhile (2 threads might execute the same "observer" twice).
(My) Solution:
An event always fired once (and only once), even if the event itself already happened before Source is on GitHub as well.
Questions:
Are there other simpler solutions addressing this? (by simpler I mean from an outside or usage perspective)
Do you see any race conditions or things that could go wrong?
Maybe you have optimizations or simplifications to add?
Input is highly appreciated!
/// <summary>
/// Triggers if the event is invoked or was invoked before subscribing to it.
/// <para> Can be accessed safely by multiple threads.</para>
/// </summary>
public class AutoInvokeEvent<Sender, Args>
{
public delegate void EventHandle(Sender sender, Args arguments);
/// <summary>
/// Handle will be invoked if the event was triggered in the past.
/// <para>Unsubscribing happens automatically after the invocation and is redundant if done from the event handle.</para>
/// </summary>
public event EventHandle Event
{
add
{
if (!Subscribe(value))
value(m_sender, m_eventArgs);
}
remove { InternalEvent -= value; }
}
private event EventHandle InternalEvent;
// this is my personal lock implementation. in this case it is used like any other lock(object) so just ignore it
private SafeExecutor m_lock = new SingleThreadExecutor();
private volatile bool m_invoked = false;
Sender m_sender;
Args m_eventArgs;
/// <summary>
/// Invokes all subscribed handles with the given parameters.
/// <para>All calls after the first are ignored.</para>
/// </summary>
public void Invoke(Sender sender, Args args)
{
GetEventHandle(sender, args)?.Invoke(m_sender, m_eventArgs);
}
private EventHandle GetEventHandle(Sender sender, Args args)
{
return m_lock.Execute(() =>
{
if (m_invoked)
return null;
m_sender = sender;
m_eventArgs = args;
m_invoked = true;
EventHandle handle = InternalEvent;
InternalEvent = null;
return handle;
});
}
/// <returns>Returns true if subscription was successful and false if handle needs to be invoked immediately.</returns>
private bool Subscribe(EventHandle handle)
{
return m_lock.Execute(() =>
{
if (!m_invoked)
InternalEvent += handle;
return !m_invoked;
});
}
}
How the class could be used :
class Connection
{
public AutoInvokeEvent<object, EndPoint> OnDisconnect = new AutoInvokeEvent<object, EndPoint>();
public Disconnect()
{
OnDisconnect.Invoke(this, endpoint);
}
}
void main()
{
Connection connection = new Connection();
connection.OnDisconnect.Event += DoStuffOnDisconnect;
}
void DoStuffOnDisconnect(object sender, EndPoint endpoint) { }
c# multithreading thread-safety event-handling observer-pattern
c# multithreading thread-safety event-handling observer-pattern
New contributor
New contributor
edited 2 days ago
New contributor
asked 2 days ago
Oachkatzl
362
362
New contributor
New contributor
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
1
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday
add a comment |
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
1
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
1
1
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Oachkatzl is a new contributor. Be nice, and check out our Code of Conduct.
Oachkatzl is a new contributor. Be nice, and check out our Code of Conduct.
Oachkatzl is a new contributor. Be nice, and check out our Code of Conduct.
Oachkatzl is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207494%2fthreadsafe-oneshot-event-which-fires-on-subscription-if-the-event-was-fired-in-t%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
What do you need this actually for? I cannot come up with any use case.
– t3chb0t
2 days ago
pretty much for what i described in the original post, a threadsafe disconnect event which is always called, even if the event fired in the past but never twice. it is a pretty convenient guarantee on which i can build other logic in a highly multithreaded environment.
– Oachkatzl
2 days ago
Mhmm, still not getting it. I was hoping you could name the exact application you're going to use this for but this explanation is too general and I cannot place it anywhere. Reading files, calculating something, downloading something, I don't know, you must be using it for something specific?
– t3chb0t
yesterday
1
oh, yes - it is a server which lets users access and control their PC with an android device. i am using the same principle for all my connections though. The object that is using the connection is for example a User-Object which needs to be aware if the user is still connected and also react to their disconnect in general. This is where this event comes into play.
– Oachkatzl
yesterday