【问题标题】:c# multi threading with simultaneous access on a listbox > data lost (pick/remove)c#多线程同时访问列表框>数据丢失(选择/删除)
【发布时间】:2013-01-04 19:19:29
【问题描述】:

我有一个带有 URL 列表的 ListBox。

我有 2 个线程获取这些 URL 并将它们处理成一个函数。

我的线程 1 使用 ListBox 的 items[0],我的线程 2 使用 items[1]

线程捡起物品后,立即使用Items.RemoveAt(0 or 1)将其删除

我使用这种方法的问题是有些 URL 被处理了两次,有些甚至没有。

有没有办法标记一个 URL 或其他东西?我对多线程不是很熟悉

PS:在我的示例中,我说我使用了 2 个线程,实际上我使用了 5 个线程。

提前致谢

编辑: 使用concurentqueue系统:

    Thread th1;
    Thread th2;
    Thread th3;
    Thread th4;
    Thread th5;
    ConcurrentQueue<string> myQueue= new ConcurrentQueue<string>();
    Int queueCount = 0;

    private void button2_Click(object sender, EventArgs e)
    {
    //initialize objects and query the database
        DBconnect conn;
        conn = new DBconnect();
        string query = "SELECT Url FROM Pages WHERE hash = ''";
        List<string> result = conn.Select(query);
        for (int i = 0; i < result.Count(); i++)
        {
    //For all rows found, add them to the queue
            myQueue.Enqueue(result[i]);
        }
    //start the 5 threads to process the queue              
        th1 = new Thread(ProcessTorrent);
        th2 = new Thread(ProcessTorrent);
        th3 = new Thread(ProcessTorrent);
        th4 = new Thread(ProcessTorrent);
        th5 = new Thread(ProcessTorrent);
        th1.Start();
        th2.Start();
        th3.Start();
        th4.Start();
        th5.Start();

    }


    private void ProcessTorrent()
    {
    //Start an unlimted task with continueWith
        Task tasks = Task.Factory.StartNew(() =>
        {
    //Check if there are still items in the queue
            if (myQueue.Count > 0)
            {
                string queueURL;
                bool haveElement = myQueue.TryDequeue(out queueURL);
        //check if i can get an element from the queue
                if (haveElement)
                {
        //start function to parse the URL and increment the number of items treated from the queue
                    get_torrent_detail(queueElement);
                    Interlocked.Increment(ref queueCount);
                    this.Invoke(new Action(() => label_total.Text = (myQueue.Count() - queueCount).ToString()));

                }
            }
        });
    //continue the task for another queue item
        tasks.ContinueWith(task =>
        {
            ProcessTorrent();
        });
    }

【问题讨论】:

  • 只有主线程(GUI Thread)才能访问像ListBox这样的GUI组件。如果你使用后台线程来访问一个 GUI 组件,它最终会失败。
  • 你应该使用ConcurrentQueue&lt;T&gt;
  • if (myQueue.Count &gt; 0) 是非常错误的。摆脱它。
  • 您的标签文字也有误。您应该将原始项目数存储在单独的字段中。

标签: c# multithreading thread-safety simultaneous-calls


【解决方案1】:

听起来您正在使用 UI 控件来协调多个线程之间的任务。

这是一个非常糟糕的主意。

相反,您应该将任务排队到ConcurrentQueue&lt;T&gt;BlockingCollection&lt;T&gt;,并让其他线程从队列中取出项目并处理它们。

【讨论】:

  • 拥有多个后台工作人员从根本上来说没什么不好,你知道的。特别是使用现代 UI,其中列表不是“UI 控件”,而是您将数据绑定到 UI 中的列表。
  • @TomTom:我不是这么说的。他不应该为此使用 ListBox。
  • @SLaks 谢谢你的信息,我用解决方案编辑了我的帖子!
【解决方案2】:

是的,这是因为 oyu 不同步对列表的访问。

基本看文档C#,LOCK语句。访问列表时加锁。这样可以防止多个线程同时访问它。

然后您总是会立即将顶部项目 (items[0]) 删除。

我对多线程不是很熟悉

我真的很喜欢人们表现出这种态度。你能想象一个厨师,作为一名专业厨师在餐馆工作,说“啊,我不熟悉烤箱,你知道”。或者医生说“好吧,我这里有问题,我不知道如何打针”。鉴于今天我们生活在一个五彩缤纷的世界中,这句话简直是在以一种糟糕的方式尖叫。

【讨论】:

  • 盲目地使用锁来创建“线程安全”的代码同样糟糕。
  • 上帝禁止有人在学习如何做多线程并提到他们并不真正熟悉它。如果他是这方面的专家,他就不需要问这个问题了。
  • 你的意思可能是多核的,但是,是的,我们也是多色的……但是这适用。另外,对于 GUI 开发人员来说,对线程一无所知是完全没问题的……对于许多从事业务应用程序的人来说,这是一种不幸的状态
  • @Alex 废话。对不起。尤其是 UI 开发人员,考虑到每个花费超过 0.1 秒的操作都应该发生在单独的线程上,应该了解锁、多线程并通过调度程序访问 UI 线程,这样他就不会使应用程序挂起。这是当今 UI 代码的基本知识。
  • 可用性。 0.1 秒是 10 年前,仍然是用户开始受到干扰的时间框架胜利。我的旧规则 - 自 2000 年之前:0.1 秒:单独的线程,1 秒:在视觉上阻止 UI 并提供一些进度指示 - 要么是条形,要么至少是一个旋转符号,这取决于它应该花费多长时间,所以可怜的用户是没有完全留在黑暗中,点击对接就像应用程序崩溃一样。请注意,“反馈”可以是“阻止按钮”,这有时是有意义的。但这是旧的可用性规则,即没有“以某种方式挂起”的应用程序。
猜你喜欢
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 2023-03-29
  • 1970-01-01
相关资源
最近更新 更多