你如何将对象放在另一个线程中?

时间:2010-07-06 08:09:07

标签: c# multithreading

在c#中有没有办法将对象放在另一个线程中?我发现的是如何在另一个线程中实际执行某些方法。我真正想要做的是在新线程中实例化一个对象,以便以后使用它提供的方法。

希望你能帮助我, 俄

9 个答案:

答案 0 :(得分:25)

对象实际上不属于某个线程。如果您有对象的引用,则可以从许多线程访问它。

这可能会给对象带来问题,这些对象不是从许多线程访问的,比如(几乎所有)System.Windows.Forms类,以及对COM对象的访问。

如果您只想从同一个线程访问对象,请在对象(或包装对象)中存储对线程的引用,并通过该线程执行方法。

答案 1 :(得分:15)

关于线程如何在这里工作似乎有些混乱,所以这是一个入门(非常简短,所以在进一步尝试多线程编程之前你应该找到更多的材料。)

对象和内存本质上是多线程的,因为进程中的所有线程都可以在选择时访问它们。

所以对象与线程没有任何关系。

但是,代码在一个线程中执行,它是代码执行的线程,你可能正在执行。

不幸的是,没有办法只是“将对象放入不同的线程”,你需要专门启动一个线程并指定在该线程中执行的代码。因此,该代码使用的对象可以“说”属于该线程,尽管这是您自己强加的人为限制。

所以没有办法做到这一点:

SomeObject obj = new SomeObject();
obj.PutInThread(thatOtherThread);
obj.Method(); // this now executes in that other thread

事实上,许多新的多线程程序员遇到的常见陷阱是,如果他们在一个线程中创建一个对象,并从另一个线程调用它的方法,那么所有这些方法都在创建该对象的线程中执行。这是不正确的,方法总是在调用它们的线程中执行。

所以以下内容也是错误的:

Thread 1:
    SomeObject obj = new SomeObject();

Thread 2:
    obj.Method(); // executes in Thread 1

此处的方法将在线程2中执行。使方法在原始线程中执行的唯一方法是与原始线程协作并“请求它”执行该方法。你如何做到这一点取决于具体情况,有很多方法可以做到这一点。

总结一下你想要的:你想创建一个新线程,并在该线程中执行代码。

要做到这一点,请查看.NET的Thread类。

但请注意:多线程应用程序非常难以正确使用,我不会为程序添加多线程功能,除非:

  1. 这是获得更多性能的唯一途径
  2. 而且,你知道你在做什么

答案 2 :(得分:8)

进程的所有线程共享相同的数据(忽略线程本地存储),因此不需要在线程之间显式迁移对象。

internal sealed class Foo
{
    private Object bar = null;

    private void CreateBarOnNewThread()
    {
        var thread = new Thread(this.CreateBar);

        thread.Start();

        // Do other stuff while the new thread
        // creates our bar.
        Console.WriteLine("Doing crazy stuff.");

        // Wait for the other thread to finish.
        thread.Join();

        // Use this.bar here...
    }

    private void CreateBar()
    {
        // Creating a bar takes a long time.
        Thread.Sleep(1000);            

        this.bar = new Object();
    }
}

答案 3 :(得分:2)

所有线程都可以看到堆栈 ,所以如果线程有你需要的对象的引用(例如通过方法传入),那么线程可以使用那些对象。这就是为什么在多线程时必须非常小心地访问对象,因为两个线程可能会尝试同时更改对象。

.NET中有一个ThreadLocal<T>类可用于将变量限制为特定线程:请参阅http://msdn.microsoft.com/en-us/library/dd642243.aspxhttp://www.c-sharpcorner.com/UploadFile/ddoedens/UseThreadLocals11212005053901AM/UseThreadLocals.aspx

答案 4 :(得分:1)

使用ParameterizedThreadStart将对象传递给您的主题。

答案 5 :(得分:0)

“供以后使用它提供的方法。”

使用包含在新线程和其他数据和方法上执行的方法的类,您可以从线程获取新线程中的数据和方法的访问权。

但是......如果你从类中执行一个方法,那么你正在当前的线程上执行。

要在新线程上执行该方法,需要一些线程同步。

System.Windows.Forms.Control.BeginInvoke这样做,Control线程一直等到请求到来。

WaitHandle 课程可以帮到你。

答案 6 :(得分:0)

很抱歉重复一些以前的工作,但OP说

  

我真正想要做的是在新线程中实例化一个对象,以便以后使用它提供的方法。

让我将其解释为:

  

我真正想做的是让一个新线程实例化一个对象,以便以后我可以使用该对象的方法。

如果我错过了标记,请为我纠正。这是一个例子:

namespace  silly
{
    public static class Program
    {
        //declared volatile to make sure the object is in a consistent state
        //between thread usages -- For thread safety.
        public static volatile Object_w_Methods _method_provider = null;
        static void Main(string[] args)
        {
            //right now, _method_provider is null.
            System.Threading.Thread _creator_thread = new System.Threading.Thread(
                new System.Threading.ThreadStart(Create_Object));
            _creator_thread.Name = "Thread for creation of object";
            _creator_thread.Start();

            //here I can do other work while _method_provider is created.
            System.Threading.Thread.Sleep(256);

            _creator_thread.Join();

            //by now, the other thread has created the _method_provider
            //so we can use his methods in this thread, and any other thread!

            System.Console.WriteLine("I got the name!!  It is: `" + 
                _method_provider.Get_Name(1) + "'");

            System.Console.WriteLine("Press any key to exit...");
            System.Console.ReadKey(true);

        }
        static void Create_Object()
        {
            System.Threading.Thread.Sleep(512);
            _method_provider = new Object_w_Methods();
        }
    }
    public class Object_w_Methods
    {
        //Synchronize because it will probably be used by multiple threads,
        //even though the current implementation is thread safe.
        [System.Runtime.CompilerServices.MethodImpl( 
            System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
        public string Get_Name(int id)
        {
            switch (id)
            {
                case 1:
                    return "one is the name";
                case 2:
                    return "two is the one you want";
                default:
                    return "supply the correct ID.";
}}}}

答案 7 :(得分:0)

就像详细说明以前的答案一样。为了回到问题,所有线程共享对象和内存空间。所以它们总是被共享,但我假设您希望安全地这样做,并使用另一个线程创建的结果。

首先尝试一种可信的C#模式。 Async Patterns  有一些设置模式可以在线程之间传输基本消息和数据。 通常,一个威胁在计算结果后就完成了!

生命威胁:在异步和共享生命威胁数据时,没有什么是万无一失的。 因此,如果您确实需要走这条路线并尝试遵循已知的模式,那么基本上要尽可能简单。

所以现在我想详细说明为什么一些已知的模式具有某种结构:

Eventargs:在传递对象之前创建对象的深层复制。 (这不是万无一失的,因为某些引用可能仍然是共享的。) 使用基本类型(如int浮点数等)传递结果。这些可以在构造函数上创建并使其成为不可变的。

原子关键词这些类型,或创建监视器等。坚持一个线程读取其他写入。

假设您有复杂的数据,您希望同时在两个线程上使用一种完全不同的方法来解决这个问题,我还没有测试过: 您可以将结果存储在数据库中,让其他可执行文件读取它。 (在行级别上会出现锁定,但您可以再次尝试或更改SQL代码,至少会报告可以通过良好设计解决的死锁,而不仅仅是挂起软件!)我只会这样做,如果它实际上是由于其他原因将数据存储在数据库中的意义。

另一种有用的方法是编写F#。默认情况下,对象和所有类型都是不可变的/所以你想要共享的对象应该有一个构造函数,没有方法允许对象被更改或基本类型增加。 所以你创建它们然后它们不会改变!所以在那之后它们是不可变的。 锁定它们并使它们平行工作变得更加容易。不要在C#类中疯狂,因为其他人可能会遵循这个“约定”,而大多数事情如Lists只是在C#中不是不可变的(readonly与immutable不同,const是非常有限的)。 Immutable versus readonly

答案 8 :(得分:-1)

如果您在线程中运行的方法驻留在自定义类中,则可以让此类的成员保存参数。

public class Foo
{
   object parameter1;
   object parameter2;

   public void ThreadMethod()
   {
       ...
   }
}