Partager via


Présentation des threads de lecteur d’objet de service (documentation du SDK POS pour .NET v1.14)

La plupart des objets de service doivent être en mesure de répondre aux événements matériels de manière asynchrone en démarrant un thread de lecteur matériel distinct. Les objets de service sont le lien entre l’application du point de service et le matériel. Par conséquent, les objets de service doivent lire les données du matériel associé tout en étant toujours disponibles pour l’application.

Cette section montre une façon d’implémenter le code nécessaire pour les objets de service multithread.

Spécifications

Pour compiler ce code, l’application doit inclure une référence à l’espace de noms System.Threading.

L’exemple ci-dessous implémente une classe d’assistance de threading qui peut être utilisée par les implémentations d’objet de service, mais ne compile pas ou ne s’exécute pas seule.

Illustre le

Cet exemple montre comment les objets de service peuvent utiliser le threading pour prendre en charge la surveillance des événements matériels de manière asynchrone. L’exemple de code implémente une classe d’assistance de thread qui peut être utilisée pour ajouter la prise en charge de thread de base à un objet service.

Pour utiliser la classe thread helper fournie dans cette section, vous devez créer une classe dérivée de ServiceObjectThreadHelper, qui est incluse dans le code ci-dessous, et implémenter les méthodes suivantes :

  • ServiceObjectThreadOpen Cette méthode est appelée à partir de la méthode OpenThread de la classe thread helper une fois l’initialisation terminée. Implémentez ici tout code d’initialisation spécifique au matériel. Cette méthode est virtual. L'implémentation par défaut retourne simplement.

  • ServiceObjectThreadClose Cette méthode est appelée lorsque l’objet d’assistance de thread termine son thread ou lors de l’appel de la méthode Dispose et doit être utilisé pour libérer tous les handles non managés ou autres ressources liées à l’appareil. Cette méthode est virtual. L'implémentation par défaut retourne simplement.

  • ServiceObjectProcedure Cette méthode est appelée une fois que toute l’initialisation a eu lieu et que le thread a été démarré avec succès. Cette méthode est abstraite et doit être implémentée dans la classe dérivée de la classe d’assistance de thread. La méthode ServiceObjectProcedure prend un seul argument, un handle ManualEvent. Votre procédure de thread doit se fermer lorsque ce handle est défini. Pour ce faire, appelez ManualEvent.WaitOne dans une boucle while . Par exemple :

    
        while (true)
        {
            // Wait for a hardware event or the thread stop event.
    
            // Test to see if the thread terminated event is set and
            // exit the thread if so.
            if (ThreadStopEvent.WaitOne(0, false))
            {
               break;
            }
    
            // The thread is not terminating, so it must be a
            // a hardware event.
        }
    

Exemple

using System;
using System.Threading;
using Microsoft.PointOfService;

namespace Samples.ServiceObjects.Advanced
{
    // The following code implements a thread helper class.
    // This class may be used by other Point Of Service
    // samples which may require a separate thread for monitoring
    // hardware.
    public abstract class ServiceObjectThreadHelper : IDisposable
    {
        // The thread object which will wait for data from the POS
        // device.
        private Thread ReadThread;

        // These events signal that the thread is starting or stopping.
        private AutoResetEvent ThreadTerminating;
        private AutoResetEvent ThreadStarted;

        // Keeps track of whether or not a thread should
        // be running.
        bool ThreadWasStarted;

        public ServiceObjectThreadHelper()
        {
            // Create events to signal the reader thread.
            ThreadTerminating = new AutoResetEvent(false);
            ThreadStarted = new AutoResetEvent(false);

            ThreadWasStarted = false;

            // You need to handle the ApplicationExit event so
            // that you can properly clean up the thread.
            System.Windows.Forms.Application.ApplicationExit +=
                        new EventHandler(Application_ApplicationExit);
        }

        ~ServiceObjectThreadHelper()
        {
            Dispose(true);
        }

        public virtual void ServiceObjectThreadOpen()
        {
            return;
        }

        public virtual void ServiceObjectThreadClose()
        {
            return;
        }

        // This is called when the thread starts successfully and
        // will be run on the new thread.
        public abstract void ServiceObjectThreadProcedure(
                AutoResetEvent ThreadStopEvent);

        private bool IsDisposed = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                try
                {
                    if (disposing == true)
                    {
                        CloseThread();
                    }
                }
                finally
                {
                    IsDisposed = true;
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);

            // This object has been disposed of, so no need for
            // the GC to call the finalization code again.
            GC.SuppressFinalize(this);
        }

        public void OpenThread()
        {
            try
            {
                // Check to see if this object is still valid.
                if (IsDisposed)
                {
                    // Throw system exception to indicate that
                        // the object has already been disposed.
                    throw new ObjectDisposedException(
                            "ServiceObjectSampleThread");
                }

                // In case the application has called OpenThread
                // before calling CloseThread, stop any previously
                // started thread.
                SignalThreadClose();

                ServiceObjectThreadOpen();

                // Reset event used to signal the thread to quit.
                ThreadTerminating.Reset();

                // Reset the event that used by the thread to signal
                // that it has started.
                ThreadStarted.Reset();

                // Create the thread object and give it a name. The
                // method used here, ThreadMethod, is a wrapper around
                // the actual thread procedure, which will be run in
                // the threading object provided by the Service
                // Object.
                ReadThread = new Thread(
                        new ThreadStart(ThreadMethod));

                // Set the thread background mode.
                ReadThread.IsBackground = false;

                // Finally, attempt to start the thread.
                ReadThread.Start();

                // Wait for the thread to start, or until the time-out
                // is reached.
                if (!ThreadStarted.WaitOne(3000, false))
                {
                    // If the time-out was reached before the event
                    // was set, then throw an exception.
                    throw new PosControlException(
                            "Unable to open the device for reading",
                            ErrorCode.Failure);
                }

                // The thread has started successfully.
                ThreadWasStarted = true;
            }
            catch (Exception e)
            {
                // If an error occurred, be sure the new thread is
                // stopped.
                CloseThread();

                // Re-throw to let the application handle the
                // failure.
                throw;
            }
        }

        private void SignalThreadClose()
        {
            if(ThreadTerminating != null && ThreadWasStarted)
            {
                // Tell the thread to terminate.
                ThreadTerminating.Set();

                // Give the thread a few seconds to end.
                ThreadStarted.WaitOne(10000, false);

                // Mark the thread as being terminated.
                ThreadWasStarted = false;
            }
        }

        public void CloseThread()
        {
            // Signal the thread that it should stop.
            SignalThreadClose();

            // Call back into the SO for any cleanup.
            ServiceObjectThreadClose();
        }

        private void Application_ApplicationExit(
                            object sender,
                            EventArgs e)
        {
            SignalThreadClose();
        }

        // This is the method run on the new thread. First it signals
        // the caller indicating that the thread has started
        // correctly. Next, it calls the service object's thread
        // method which will loop waiting for data or a signal
        // to close.
        private void ThreadMethod()
        {
            try
            {
                // Set the event to indicate that the thread has
                // started successfully.
                ThreadStarted.Set();

                // Call into the thread procedure defined by the
                // Service Object.
                ServiceObjectThreadProcedure(ThreadTerminating);

                // Signal that the thread procedure is exiting.
                ThreadStarted.Set();
            }
            catch (Exception e)
            {
                Logger.Info("ServiceObjectThreadHelper",
                        "ThreadMethod Exception = " + e.ToString());
                throw;
            }
        }
    }
}

Voir aussi

Tâches

Autres ressources