// Singleton class CollectionObject
public class CollectionObject
{
private static CollectionObject instance = null;
// GetInstance() is not called from multiple threads
public static CollectionObject GetInstance()
{
if (CollectionObject.instance == null)
CollectionObject.instance = new CollectionObject();
return CollectionObject.instance;
}
// Dictionary object contains Service ID (int) as key and Service object as the value
// Dictionary is filled up during initiation, before the method call ReadServiceMatrix detailed underneath
public Dictionary<int, Service> serviceCollectionDictionary = new Dictionary<int,Service>();
public Service GetServiceByIDFromDictionary(int servID)
{
if (this.serviceCollectionDictionary.ContainsKey(servID))
return this.serviceCollectionDictionary[servID];
else
return null;
}
}
DataTable serviceMatrix = new DataTable();
// Fill serviceMatrix data table from the database
private int ReadServiceMatrix()
{
// Access the Singleton class object
CollectionObject collectionObject = CollectionObject.GetInstance();
// Parallel processing of the data table rows
Parallel.ForEach<DataRow>(serviceMatrix.AsEnumerable(), row =>
{
//Access Service ID from the Data table
string servIDStr = row["ServID"].ToString().Trim();
// Access other column details for each row of the data table
string currLocIDStr = row["CurrLocId"].ToString().Trim();
string CurrLocLoadFlagStr = row["CurrLocLoadFlag"].ToString().Trim();
string nextLocIDStr = row["NextLocId"].ToString().Trim();
string nextLocBreakFlagStr = row["NextLocBreakFlag"].ToString().Trim();
string seqStr = row["Seq"].ToString().Trim();
int servID = Int32.Parse(servIDStr);
int currLocID = Int32.Parse(currLocIDStr);
int nextLocID = Int32.Parse(nextLocIDStr);
bool nextLocBreakFlag = Int32.Parse(nextLocBreakFlagStr) > 0 ? true : false;
bool currLocBreakFlag = Int32.Parse(CurrLocLoadFlagStr) > 0 ? true : false;
int seq = Int32.Parse(seqStr);
// Method call leading to the issue (definition in Collection Object class)
// Fetch service object using the Service ID from the DB
Service service = collectionObject.GetServiceByIDFromDictionary(servID);
// Call a Service class method
service.InitLanes.Add(new Service.LaneNode(currLoc.SequentialID, currLocBreakFlag, nextLoc.SequentialID, nextLocBreakFlag, seq));
}
問題發生的:
在上面的代碼在字典中的所有服務對象,後續方法調用沒有進行,導致進一步處理中的問題。它必須以並行方式從字典中提取服務對象
db一個字典包含所有的Ids /服務對象,但我的理解是在並行模式下處理Singleton類時,幾個對象被跳過導致這個問題。
在我的理解中,傳遞的服務ID和創建的服務對象都是線程本地的,所以不應該存在我面臨的問題。這種問題是唯一可能的,當一個給定的方法調用一個線程替換另一個線程的服務id值,因此最終會得到Service對象,並且少數被跳過,這在我看來是奇怪的,直到和除非我做不知道在這種情況下正確
目前我能夠通過使用foreach循環,而不是Parallel.ForEach/Parallel.Invoke
請參閱運行非線程模式相同的代碼多線程並讓我知道你的觀點或任何可以幫助我解決問題的指針
感謝斯科特,這的確是問題,我並沒有意識到,多個線程越來越相同的服務對象,從而導致問題,InitLanes是一種自定義數據結構,它以非線程模式廣泛訪問,將它轉換爲線程安全列表是否明智,是否會影響非線程訪問。目前正如建議我使用鎖對象 –
由於'InitLanes'是一個自定義數據結構,您只需要通過該類,並確保它正確鎖定以防止內部狀態被混淆。 ['ReaderWriterLock'](http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock%28v=vs.110%29.aspx)在這個轉換中可能會有很大的幫助。它將允許許多讀者同時訪問課程,但只要有一個作者阻止了訪問,這樣就不會有讀者或作者訪問受保護區域,而鎖定位置不在鎖定位置。 –