簡體   English   中英

如何同步這兩個線程?

[英]How can I synchronize these two threads?

這是課程:

public class Ticker
{
    public event EventHandler Tick;
    public EventArgs e = null;
    public void TickIt()
    {
        while (true)
        {
            System.Threading.Thread.Sleep(300);
            if (Tick != null)
            {
                Tick(this, e);
            }
        }
    }

我在Windows窗體中運行兩個線程:

public partial class Form1 : Form
{
    Ticker ticker1 = new Ticker();
    Ticker ticker2 = new Ticker();
    Thread t;
    Thread t1;

    public Form1()
    {
        InitializeComponent();
        ticker1.Tick += ticker1_Tick;
        ticker2.Tick += ticker2_Tick;

        t = new Thread(new ThreadStart(ticker1.TickIt));
        t1 = new Thread(new ThreadStart(ticker2.TickIt)));
        t.Start();
        t1.Start();

    }
    public void ticker1_Tick(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((MethodInvoker)delegate
            {
                ticker1_Tick(sender, e);
            });
            return;
        } 


        richTextBox1.Text += "t1 ";
    }
    public void ticker2_Tick(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((MethodInvoker)delegate
            {
                ticker2_Tick(sender, e);
            });
            return;
        } 


        richTextBox2.Text += "t2 ";
    }

問題是線程t在幾秒鍾之后比t1提前了幾秒鍾。

首先,為什么會發生這種情況,這是沒有意義的,因為每個線程應在滴答之前等待300毫秒?

其次,我該如何同步這兩個線程,以便它們同時進行跳動,而一個線程又不能領先另一個線程?

我不能在while循環之前放一個鎖,然后只有一個線程在運行,而另一個線程被鎖定。 把鎖放在別處不會改變任何東西。

我認為您不能相信sleep(300)來保持線程獨立運行相同的次數...

您可以做的一件事是擁有一個中央計時器/滴答生成器,該信號在每個滴答中發出一個同步對象信號,並且線程函數僅滴答一次,然后WaitsForObject從主線程生成下一個滴答,實際上有一個計時器和告訴線程同步滴答。

還要注意,訂閱線程函數事件的方式需要在處理函數中考慮競爭條件。 每個方法都將在其自己的線程上運行(直到begininvoke),因此,如果您訪問任何資源(類字段等),則這些資源需要同步。 忘記線程發生了什么太容易了。 :(

如果您確實需要它們完全同步並按一定順序執行刻度,則需要Jaime提到的某種中央計時器。 如果您需要獨立的時序,但又想防止由於睡眠的不精確性或執行事件處理程序所花費的時間而增加延遲,則可以使用以下方法:

public class Ticker
{
    public event EventHandler Tick;
    public EventArgs e = null;
    public void TickIt()
    {
        const int targetSleepTime = 300;
        int nextTick = Environment.TickCount + targetSleepTime;
        while (true)
        {
            System.Threading.Thread.Sleep(Math.Max(nextTick - Environment.TickCount, 0));
            if (Tick != null)
            {
                Tick(this, e);
            }
            nextTick += targetSleepTime;
        }
    }
}

請記住,Environment.TickCount可以在返回到Int32.MaxValue時返回到Int32.MinValue。 您將需要額外的代碼來處理該問題,或者可能基於DateTime.UtcNow(比DateTime.Now少的開銷)來計時。

使用AutoResetEvent怎么樣?

class Program
{
    static readonly AutoResetEvent thread1Step = new AutoResetEvent(false);
    static readonly AutoResetEvent thread2Step = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        new Thread(new ThreadStart(Thread1Main)).Start();
        new Thread(new ThreadStart(Thread2Main)).Start();
    }

    private static void Thread1Main()
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            Console.WriteLine("thread1 i=" + i);
            thread1Step.Set();
            thread2Step.WaitOne();
        }
    }

    private static void Thread2Main()
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            Console.WriteLine("thread2 i=" + i);
            thread2Step.Set();
            thread1Step.WaitOne();
        }
    }
}

好吧,如果您使用的是.NET 4.0,則可以使用Barrier,但是您必須將其放入Ticker類中,否則會阻塞UI線程。

http://msdn.microsoft.com/zh-CN/library/system.threading.barrier.aspx

在您的股票報價器類中,增加輪詢頻率並檢查系統計時器,直到達到所需的時間間隔為止。 如果可以毫秒精度運行,則可以使用TickCountTicks;如果系統支持,可以使用StopWatch以獲得更高的精度。

為了使它們保持同步,它們在開始時需要一個公共參考。 你可以通過這個作為未來特定剔開始同步或使用類似Tick模量100或輪詢為表示何時開始共享靜態標志。

您不能具有絕對的精度,因此請從一開始就定義您可以使用的精度范圍,例如,股票代號線程之間的正負5ms。

可以幫助您解決的一件事是啟動一個共享的靜態StopWatch實例,並在所有日志記錄中回顯其經過的時間,以幫助您確定應用程序中的任何延遲。

暫無
暫無

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

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