导航

实现ISynchronizeInvoke

Posted on 2006-09-15 08:55  hcfalan  阅读(2411)  评论(6编辑  收藏  举报

实现ISynchronizeInvoke

        当运行于线程T1的客户端调用一个对象的方法的时候,该对象的方法是在客户端线程上执行的。然而,如果该对象的方法要求始终在一个指定线程T2上执行,该怎么实现呢?这是要求多个线程配合使用的常见情形。例如,.NET Windows窗体和控件要求必须在创建它们的那个线程里处理消息。为了处理这样的情况,.NET提供了ISynchronizeInvoke接口。本文演示了如何实现ISynchronizeInvoke接口,Synchronizer类。Synchronizer类是ISynchronizeInvoke接口的一个通用实现。你可以继承它来进行扩充,也可以直接使用它作为你实现ISynchronizeInvoke的类的成员,代理ISynchronizeInvoke的行为。

public delegate int AddDelegate(int arg1, int arg2);

public class Calculator
{
    
public int Add(int arg1, int arg2)
     
{
         
int threadId = Thread.CurrentThread.GetHashCode();
        Console.WriteLine(
"Calculator thread ID is " + threadId.ToString());
        Thread.Sleep(
5000);
        
return arg1 + arg2;
    }

}

[Serializable]
class WorkItem : IAsyncResult
{
    
object[] mArgs;
    
object mAsyncState;
    
bool mCompleted;
    Delegate mMethod;
    ManualResetEvent mEvent;
    
object mMethodReturnedValue;
    
    
public WorkItem(object asyncState, Delegate method, object[] args)
    
{
        mAsyncState 
= asyncState;
        mMethod 
= method;
        mArgs 
= args;
        mEvent 
= new ManualResetEvent(false);
        mCompleted 
= false;
    }

    
    
//IAsyncResult properties 
    object IAsyncResult.AsyncState
    
{
        
get return mAsyncState; }
    }

    
    WaitHandle IAsyncResult.AsyncWaitHandle
    
{
        
get return mEvent; }
    }

    
    
bool IAsyncResult.CompletedSynchronously
    
{
        
get return false; }
    }

    
    
bool IAsyncResult.IsCompleted
    
{
        
get return mCompleted; }
    }

    
    
bool Completed
    
{
        
get lock(thisreturn mCompleted; } }
        
set lock(this{ mCompleted = value;} }
    }

    
    
public void CallBack()
    
{
        MethodReturnedValue 
= mMethod.DynamicInvoke(mArgs);
        mEvent.Set();
        Completed 
= true;
    }

    
    
public object MethodReturnedValue
    
{
        
get 
        
{
            
object methodReturnedValue;
            
lock (this)
            
{
                methodReturnedValue 
= mMethodReturnedValue;
            }

            
return methodReturnedValue;
        }

        
set
        
{
            
lock (this)
            
{
                mMethodReturnedValue 
= value;
            }

        }

    }
        
}

 

 

class WorkerThread
{
    
public Thread mThreadObj;
    
bool mEndLoop;
    Mutex mEndLoopMutex;
    AutoResetEvent mItemAdded;
    Synchronizer mSynchronizer;
    Queue mWorkItemQueue;
    
    
public WorkerThread(Synchronizer synchronizer)
    
{
        mSynchronizer 
= synchronizer;
        mEndLoop 
= false;
        mThreadObj 
= null;
        mEndLoopMutex 
= new Mutex();
        mItemAdded 
= new AutoResetEvent(false);
        mWorkItemQueue 
= new Queue();
        CreateThread(
true);
    }

    
    
public void QueueWorkItem(WorkItem workItem)
    
{
        
lock (mWorkItemQueue.SyncRoot)
        
{
            mWorkItemQueue.Enqueue(workItem);
            mItemAdded.Set();
        }

    }

    
    
bool EndLoop
    
{
        
get
        
{
            
bool result = false;
            mEndLoopMutex.WaitOne();
            result 
= mEndLoop;
            mEndLoopMutex.ReleaseMutex();
            
return result;
        }

        
set
        
{
            mEndLoopMutex.WaitOne();
            mEndLoop 
= value;
            mEndLoopMutex.ReleaseMutex();
        }

    }

    
    Thread CreateThread(
bool autoStart)
    
{
        
if (mThreadObj != null)
        
{
            Debug.Assert(
false);
            
return mThreadObj;
        }

        ThreadStart threadStart 
= new ThreadStart(Run);
        mThreadObj 
= new Thread(threadStart);
        mThreadObj.Name 
= "Synchronizer Worker Thread";
        
if (autoStart)
        
{
            mThreadObj.Start();
        }

        
return mThreadObj;
    }

    
    
void Start()
    
{
        Debug.Assert(mThreadObj 
!= null);
        Debug.Assert(mThreadObj.IsAlive 
== false);
        mThreadObj.Start();
    }
    
    
    
bool QueueEmpty
    
{
        
get
        
{
            
lock (mWorkItemQueue.SyncRoot)
            
{
                
if (mWorkItemQueue.Count > 0)
                    
return false;
                
return true;
            }

        }

    }

    
    WorkItem GetNext()
    
{
        
if (QueueEmpty) return null;
        
lock (mWorkItemQueue.SyncRoot)
        
{
            
return (WorkItem)mWorkItemQueue.Dequeue();
        }

    }

    
    
void Run()
    
{
        
while (EndLoop == false)
        
{
            
while (QueueEmpty == false)
            
{
                
if (EndLoop)
                    
return;
                WorkItem workItem 
= GetNext();
                workItem.CallBack();
            }

            mItemAdded.WaitOne();
        }

    }

    
    
public void Kill()
    
{
        Debug.Assert(mThreadObj 
!= null);
        
if (mThreadObj.IsAlive == false)
        
{
            
return;
        }

        EndLoop 
= true;
        mItemAdded.Set();
        
        
// wait for thead to die
        mThreadObj.Join();
        
if (mEndLoopMutex != null)
            mEndLoopMutex.Close();
        
if (mItemAdded != null)
            mItemAdded.Close();
    }

}

 

 

public class Synchronizer: ISynchronizeInvoke,IDisposable
{
    WorkerThread mWorkerThread;
    
    
public bool InvokeRequired
    
{
        
get
        
{
            
bool res = Object.ReferenceEquals(Thread.CurrentThread, mWorkerThread.mThreadObj);
            
return res;
        }

    }

    
    
public IAsyncResult BeginInvoke(Delegate method, Object[] args)
    
{
        WorkItem result 
= new WorkItem(null, method, args);
        mWorkerThread.QueueWorkItem(result);
        
return result;
    }

    
    
public object EndInvoke(IAsyncResult result)
    
{
        result.AsyncWaitHandle.WaitOne();
        WorkItem workItem 
= (WorkItem)result;
        
return workItem.MethodReturnedValue;
    }

    
    
public object Invoke(Delegate method, object[] args)
    
{
        IAsyncResult asyncResult;
        asyncResult 
= BeginInvoke(method,args);
        
return EndInvoke(asyncResult);
    }

    
    
public Synchronizer()
    
{
        mWorkerThread 
= new WorkerThread(this);
    }

    
    
~Synchronizer()
    
{
    }

    
    
public void Dispose()
    
{
        mWorkerThread.Kill();
    }

}

 

 

public class Tester : IDisposable
{
    Synchronizer mSynchronizer;
    
public Tester()
    
{
        
int threadId = Thread.CurrentThread.GetHashCode();
        Console.WriteLine(
"Main Thread Id is: " + threadId.ToString());
        mSynchronizer 
= new Synchronizer();
    }

    
    
public void TestSynchCall()
    
{
        Calculator  calc   
= new Calculator();
        AddDelegate addDelegate 
= new AddDelegate(calc.Add);
        
object[] arr = new object[2];
        arr[
0= 15;
        arr[
1= 38;
        
object sum = 0;
        sum 
= mSynchronizer.Invoke(addDelegate,arr);
        Console.WriteLine(
"TestSynchCall: result is " + sum.ToString());
    }

    
    
public void TestAsyncCall()
    
{
        Calculator  calc   
= new Calculator();
        AddDelegate addDelegate 
= new AddDelegate(calc.Add);
        
object[] arr = new object[2];
        arr[
0= 33;
        arr[
1= 19;
        IAsyncResult result  
= mSynchronizer.BeginInvoke(addDelegate,arr);
        
        Console.WriteLine(
"wait for get result from Async Call");
        
object sum = mSynchronizer.EndInvoke(result);
        Console.WriteLine(
"TestAsyncCall: result is " + sum.ToString());
    }

   
    
public void Dispose()
    
{
        mSynchronizer.Dispose();
    }

    
}

    
public class MyClass
{
    
public static void Main(string[] args)
    
{
        
using (Tester tester = new Tester())
        
{
            
//tester.TestSynchCall();
            tester.TestAsyncCall();
        }

        Console.ReadLine();
    }

}