簡介服務物件讀取器執行緒 (POS for .NET v1.14 SDK 文件)
大部分的服務物件都必須能夠藉由啟動個別的硬體讀取器執行緒,以非同步方式回應硬體事件。 服務物件是服務點應用程式與硬體之間的連結。 因此,服務物件必須從相關聯的硬體讀取資料,同時仍可供應用程式使用。
本節示範實作多執行緒服務物件所需程式碼的其中一種方式。
需求
若要編譯此程式碼,應用程式必須包含 System.Threading 命名空間的參考。
下列範例會實作可由 Service Object 實作使用的執行緒協助程式類別,但不會自行編譯或執行。
示範
此範例示範服務物件如何使用執行緒功能,以非同步方式支援監視硬體事件。 範例程式碼會實作執行緒協助程式類別,可用來將基本執行緒支援新增至服務物件。
若要使用本節中提供的執行緒協助程式類別,您必須建立衍生自 ServiceObjectThreadHelper 的類別,其包含在下列程式碼中,並實作下列方法:
ServiceObjectThreadOpen 初始化完成後,會從執行緒協助程式類別的 OpenThread 方法呼叫這個方法。 在這裡實作任何硬體特定的初始化程式碼。 這個方法是虛擬的。 預設實作只會傳回。
ServiceObjectThreadClose 執行緒協助程式物件終止其執行緒或呼叫 Dispose 方法時,應該用來釋放與裝置相關的任何非受控控制代碼或其他資源時,就會呼叫這個方法。 這個方法是虛擬的。 預設實作只會傳回。
ServiceObjectProcedure 所有初始化已完成而且執行緒已成功啟動後,就會叫用這個方法。 這個方法是抽象的,必須在衍生自執行緒協助程式類別的類別中實作。 ServiceObjectProcedure 方法會採用單一引數 ManualEvent 控制代碼。 設定此控制代碼時,執行緒程式必須結束。 這是藉由在 while 迴圈內呼叫 ManualEvent.WaitOne 來完成。 例如:
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. }
範例
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;
}
}
}
}