/// <summary> /// Gets the SeeingSharpMessenger by the given name. /// </summary> /// <param name="messengerName">The name of the messenger.</param> public static SeeingSharpMessenger TryGetByName(string messengerName) { messengerName.EnsureNotNullOrEmpty(nameof(messengerName)); SeeingSharpMessenger result = null; s_messengersByName.TryGetValue(messengerName, out result); return(result); }
/// <summary> /// Clears all synchronization options. /// </summary> public void DiscardGlobalSynchronization() { if (string.IsNullOrEmpty(m_messengerName)) { return; } SeeingSharpMessenger dummyResult = null; s_messengersByName.TryRemove(m_messengerName, out dummyResult); m_checkBehavior = SeeingSharpMessageThreadingBehavior.Ignore; m_messengerName = string.Empty; m_syncContext = null; }
/// <summary> /// Sends the given message to all subscribers (synchonous processing). /// </summary> /// <typeparam name="MessageType">Type of the message.</typeparam> /// <param name="message">The message to send.</param> /// <param name="isInitialCall">Is this one the initial call to publish? (false if we are coming from async routing)</param> private void PublishInternal <MessageType>( MessageType message, bool isInitialCall) where MessageType : SeeingSharpMessage { message.EnsureNotNull(nameof(message)); try { // Check whether publich is possible if (m_checkBehavior == SeeingSharpMessageThreadingBehavior.EnsureMainSyncContextOnSyncCalls) { if (!CompareSynchronizationContexts()) { throw new SeeingSharpException( "Unable to perform a synchronous publish call because current " + "SynchronizationContext is set wrong. This indicates that the call " + "comes from a wrong thread!"); } } // Notify all subscribed targets Type currentType = typeof(MessageType); // Check for correct message sources if (isInitialCall) { string[] possibleSources = s_messageSources.GetOrAdd(currentType, (inputType) => message.GetPossibleSourceThreads()); if (possibleSources.Length > 0) { string mainThreadName = m_messengerName; if (string.IsNullOrEmpty(mainThreadName) || (Array.IndexOf(possibleSources, mainThreadName) < 0)) { throw new InvalidOperationException(string.Format( "The message of type {0} can only be sent by the threads {1}. This Messenger belongs to the thread {2}, so no publish possible!", currentType.FullName, possibleSources.ToCommaSeparatedString(), !string.IsNullOrEmpty(mainThreadName) ? mainThreadName as string : "(empty)")); } } } // Perform synchronous message handling List <MessageSubscription> subscriptionsToTrigger = new List <MessageSubscription>(20); lock (m_messageSubscriptionsLock) { if (m_messageSubscriptions.ContainsKey(currentType)) { // Need to copy the list to avoid problems, when the list is changed during the loop and cross thread accesses subscriptionsToTrigger = new List <MessageSubscription>(m_messageSubscriptions[currentType]); } } // Trigger all found subscriptions List <Exception> occurredExceptions = null; for (int loop = 0; loop < subscriptionsToTrigger.Count; loop++) { try { subscriptionsToTrigger[loop].Publish(message); } catch (Exception ex) { if (occurredExceptions == null) { occurredExceptions = new List <Exception>(); } occurredExceptions.Add(ex); } } // Perform further message routing if enabled if (isInitialCall) { // Get information about message routing string[] asyncTargets = s_messagesAsyncTargets.GetOrAdd(currentType, (inputType) => message.GetAsyncRoutingTargetThreads()); string mainThreadName = m_messengerName; for (int loop = 0; loop < asyncTargets.Length; loop++) { string actAsyncTargetName = asyncTargets[loop]; if (mainThreadName == actAsyncTargetName) { continue; } SeeingSharpMessenger actAsyncTargetHandler = null; if (s_messengersByName.TryGetValue(actAsyncTargetName, out actAsyncTargetHandler)) { SynchronizationContext actSyncContext = actAsyncTargetHandler.m_syncContext; if (actSyncContext == null) { continue; } SeeingSharpMessenger innerHandlerForAsyncCall = actAsyncTargetHandler; actSyncContext.PostAlsoIfNull(() => { innerHandlerForAsyncCall.PublishInternal(message, false); }); } } } // Notify all exceptions occurred during publish progress if (isInitialCall) { if ((occurredExceptions != null) && (occurredExceptions.Count > 0)) { throw new MessagePublishException(typeof(MessageType), occurredExceptions); } } } catch (Exception ex) { // Check whether we have to throw the exception globally var globalExceptionHandler = SeeingSharpMessenger.CustomPublishExceptionHandler; bool doRaise = true; if (globalExceptionHandler != null) { try { doRaise = !globalExceptionHandler(this, ex); } catch { doRaise = true; } } // Raise the exception to inform caller about it if (doRaise) { throw; } } }
/// <summary> /// Clears this message. /// </summary> internal void Clear() { m_Messenger = null; m_messageType = null; m_targetHandler = null; }
/// <summary> /// Initializes a new instance of the <see cref="MessageSubscription"/> class. /// </summary> /// <param name="Messenger">The messenger.</param> /// <param name="messageType">Type of the message.</param> /// <param name="targetHandler">The target handler.</param> internal MessageSubscription(SeeingSharpMessenger Messenger, Type messageType, Delegate targetHandler) { m_Messenger = Messenger; m_messageType = messageType; m_targetHandler = targetHandler; }
private async void ObjectThreadMainMethod() #endif { try { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); //Set synchronization context for this thread m_syncContext = new ObjectThreadSynchronizationContext(this); #if DESKTOP SynchronizationContext.SetSynchronizationContext(m_syncContext); #endif // Do create the messenger if configured if (m_createMessenger) { m_Messenger = new SeeingSharpMessenger(); m_Messenger.ApplyForGlobalSynchronization(this); } //Notify start process try { OnStarting(EventArgs.Empty); } catch (Exception ex) { OnThreadException(new ObjectThreadExceptionEventArgs(m_currentState, ex)); m_currentState = ObjectThreadState.None; return; } //Run main-thread if (m_currentState != ObjectThreadState.None) { m_currentState = ObjectThreadState.Running; while (m_currentState == ObjectThreadState.Running) { try { //Wait for next action to perform #if DESKTOP m_mainLoopSynchronizeObject.Wait(m_heartBeat); #else await m_mainLoopSynchronizeObject.WaitAsync(m_heartBeat); #endif //Measure current time stopWatch.Stop(); m_timer.Add(stopWatch.Elapsed); stopWatch.Reset(); stopWatch.Start(); //Get current taskqueue List <Action> localTaskQueue = new List <Action>(); Action dummyAction = null; while (m_taskQueue.TryDequeue(out dummyAction)) { localTaskQueue.Add(dummyAction); } //Execute all tasks foreach (Action actTask in localTaskQueue) { try { actTask(); } catch (Exception ex) { OnThreadException(new ObjectThreadExceptionEventArgs(m_currentState, ex)); } } //Perfoms a tick OnTick(EventArgs.Empty); } catch (Exception ex) { OnThreadException(new ObjectThreadExceptionEventArgs(m_currentState, ex)); } } //Notify stop process try { OnStopping(EventArgs.Empty); } catch (Exception ex) { OnThreadException(new ObjectThreadExceptionEventArgs(m_currentState, ex)); } } //Reset state to none m_currentState = ObjectThreadState.None; stopWatch.Stop(); stopWatch = null; } catch (Exception ex) { OnThreadException(new ObjectThreadExceptionEventArgs(m_currentState, ex)); m_currentState = ObjectThreadState.None; } // Notify thread stop event try { m_threadStopSynchronizeObject.Release(); } catch (Exception) { } }