多线程共享对象 [英] Mutliple threads sharing objects

查看:74
本文介绍了多线程共享对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



想知道下图中的线程是否共享相同的队列和锁:

[代码]

Hi,

Wanted to know if my threads in the illustration below are sharing the same queue and lock:

[code]

class ThreadCls
{
   Queue q = new Queue();
   Threads[] t = new Threads[4];
   object sync = new Object();
   EventWaitHandle ewh = new AutoResetEvent(false);
   
   ThreadCls()
   {
      for(int i = 0; i < 4; i++)
      {
          t[i] = new Thread(doWork);
          t.Start();
      }
   }

   public void getData(object data)
   {
      lock(sync)
      {
          q.Enqueue(data);
      }
      ewh.Set();
   }
   public void doWork()
   {
      while(true)
      {
          lock(sync)
          {
              object o = q.Dequeue();
          }
              // processing logic...
              // etc...

         ewh.WaitOne();
      }
   }
}

推荐答案

这个问题毫无意义.当然,如果将四个线程以及锁和队列放在一个类中,并将它们设为私有,这很好,那么锁和队列是共享的.问什么?

我必须说,您朝着正确的方向前进.我看到了三个问题:

首先,数字4是硬编码的,并且在两个地方使用,这是不支持的:如果要更改数字该怎么办?您可能会在一个地方更改,而在另一个地方忘记了,依此类推.始终避免使用任何这样的立即常量 4,对于整个解决方案,仅在一个位置定义显式常量.但是为什么要使其始终不变呢?更好的是,将其抽象出来,使其成为类的参数. (也为班级起了不好的名字:切勿使用缩写).

第二个问题:数据类型object错误.它将需要类型强制转换,这是不好的.将数据类型设为通用参数,使您的类通用.

第三个问题:锁定是多余的.您只需要事件等待句柄.在许多情况下,甚至由于锁和其他同步原语的组合,您甚至可能会遇到死锁.还有一个众所周知的想法:过度同步总是不好的.这里的一些查询者询问有关那里的解决方案的一些问题,在这些解决方案中,他们如此大量地同步线程,以致于使它们完全顺序!始终完全根据需要进行同步.

现在,我可以为您提供我在CodeProject上发布的两个解决方案,它们都非常接近您的方法,但是制作更准确.首先是线程的包装器(我认为这是必须的:由于我在解决方案中解释的许多原因,使用裸"线程是不好的);另一个是阻塞队列的通用类,您可以在线程之间透明地使用它,而无需任何其他同步原语.

参见:
如何将ref参数传递给线程 [ ^ ](线程包装器),
启动后更改线程(生产者)的参数 [ ^ ](带锁的线程包装器示例),
用于线程通信和线程间调用的简单阻塞队列 [ ^ ].

祝你好运,
—SA
The question is pointless. Of course, if you put four threads and the lock and the queue in one class and made them private, which is good, the lock and queue are shared. What to ask about?

I must say, you go in the right direction. I can see three problems:

First, the number 4 is hard-coded and used in two places, which is not supportable: what if you want to change it? You might change is in one place, forget in another one, etc. Always avoid any immediate constants like this 4, use explicit constant defined only in one place for whole solution. But why making it a constant at all? Better yes, abstract it out, make it a parameter of the class. (Also bad name for a class: never use abbreviations).

Second problem: data type object is bad. It will need type casts, which is bad. Make your class generic with data type made a generic parameter.

Third problem: lock is redundant. You need only the event wait handle. In many situation, you can even get a deadlock just because of combination of lock and other synchronization primitives. There is also a well-known idea: over-synchronization is always bad. Some inquirers here asked some question about there solution where they synchronized threads so heavily that they made them completely sequential! Always synchronize exactly as much as needed.

Now, I can offer you two solutions I published here at CodeProject, both very close to your approach but made more accurately. First is a wrapper for the thread (which is I think is a must: using a "bare" thread is bad by many reasons I explain in my solution); another one is generic class for a blocking queue which you can transparently use between threads without any other synchronization primitives.

See:
How to pass ref parameter to the thread[^] (thread wrapper),
change paramters of thread (producer) after it started[^] (thread wrapper example with lock),
Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

Good luck,
—SA


这篇关于多线程共享对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆