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) { }









share|improve this question









New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • 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















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) { }









share|improve this question









New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




















  • 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













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) { }









share|improve this question









New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











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






share|improve this question









New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 2 days ago





















New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 2 days ago









Oachkatzl

362




362




New contributor




Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Oachkatzl is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • 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










  • 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















active

oldest

votes











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






Oachkatzl is a new contributor. Be nice, and check out our Code of Conduct.










 

draft saved


draft discarded


















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





































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.










 

draft saved


draft discarded


















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.















 


draft saved


draft discarded














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




















































































Popular posts from this blog

Сан-Квентин

8-я гвардейская общевойсковая армия

Алькесар