簡體   English   中英

如何為進程創建的所有線程(在C#.NET 2.0中)具有唯一的ID?

[英]How to have unique IDs for all Threads that a Process creates (in C# .NET 2.0)?

我有以下情況:

private void btn_Click(object sender, EventArgs e)
{
    Thread newThread = new Thread(Step1);
    newThread.Start(this);
}

private void Step1(object stateInfo)
{
    Register();

    // work

    Thread newThread = new Thread(Step2);
    newThread.Start(this);
}

private void Step2(object stateInfo)
{
    Register();

    // work

    Thread newThread = new Thread(Step3);
    newThread.Start(this);
}

private void Step3(object stateInfo)
{
    Register();

    // work
    // finish
}

private void Register()
{
    // adds a new entry to a Dictionary,
    // where the key is the Thread's ID (System.Threading.Thread.CurrentThread.ManagedThreadId)
    // and the value is a resource 
    // the goal is for a Thread not to register itself twice, or not to change its resource 
}

就像評論所說,我需要為每個線程節省資源。 每個線程只能執行一次,並且不可修改。

問題在於,有時,步驟3中的線程與步驟1中的線程具有相同的ID。 我認為這很有道理; 因為到第3步時,第1步的線程已經“死”,其ID可以重用。

你有什么建議嗎? 我的方法有什么問題嗎? 是否有一種方法來獲取/生成進程創建的所有線程的唯一ID?

[編輯1]包含.NET 2.0約束。

您可能應該使用ThreadLocal<T>對象或ThreadStatic靜態字段,這些對象將在線程死時被擦除,並且即使產生具有相同托管線程ID的新線程也不會被重用。

參見此處: ThreadLocalThreadStatic

線程是對象,因此您可以簡單地依賴內置的相等系統:

private Dictionary<Thread, R> store = new Dictionary<Thread, R> ();
private void Register()
{
    var r = ..
    store.Add(Thread.CurrentThread, r);
}

引用相等將確保您不會重復。 您應該知道,雖然您的詞典阻止了線程被GC。 您需要不時清理一次。

如果您不想保留線程,則可以使用Interlocked.Increment()創建自己的簡單id生成器

為了避免GC問題,@ Henk的代碼出現了問題,可以使用ConditionalWeakTable (可在.NET 4.0及更高版本上使用),這不會阻止GC收集其鍵和值。 我將long用作ID,因為這樣一來,我們就不必擔心長時間運行的應用程序中的整數溢出。

public class UniqueId<T>
    where T:class
{
    long counter = 0;
    ConditionalWeakTable<T, object> ids = new ConditionalWeakTable<T,object>();

    public long GetId(T obj)
    {
        return (long)ids.GetValue(obj, _ => Interlocked.Increment(ref counter));
    }
}

對於您的問題,您可以使用:

var ids = new UniqueId<Thread>();

ids.GetId(thread1) // will assign it the id 1
ids.GetId(thread2) // will assign it the id 2 (assuming it's a different thread)
ids.GetId(thread1) // will reuse the existing id 1

該代碼是線程安全的,因為Interlocked.Increment生成唯一的ID,而ConditionalWeakTable也是線程安全的。 但是,如果有多個線程查詢沒有ID的線程的ID,它可以跳過ID。 就像GetValue文檔中所說的那樣:

如果多個線程嘗試創建相同的鍵, createValueCallback可以使用同一鍵多次調用createValueCallback 這些調用中只有一個會成功,並且其返回值將添加到表中。 哪個線程成功創建值是不確定的。

這對於您的應用程序來說應該沒問題,但是如果不可接受,則可以使用鎖來防止多個線程同時生成ID。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM