Как вы помещаете объект в другой поток?

Есть ли способ в С# поместить объекты в другой поток? Все, что я нашел, это как выполнить некоторые методы в другом потоке. То, что я на самом деле хочу сделать, - инициализировать объект в новом потоке для последующего использования методов, которые он предоставляет.

Надеюсь, ты поможешь мне, Russo

Ответы

Ответ 1

Объекты не принадлежат нитью. Если у вас есть ссылка на объект, вы можете получить к нему доступ из многих потоков.

Это может привести к проблемам с объектом, которые не предназначены для доступа из многих потоков, например (почти всех) классов System.Windows.Forms и доступа к COM-объектам.

Если вы хотите получить доступ к объекту из того же потока, сохраните ссылку на поток в объекте (или оберточном объекте) и выполните методы через этот поток.

Ответ 2

Кажется, есть некоторая путаница относительно того, как работают нити, поэтому это праймер (очень короткий, так что вы должны найти больше материала, прежде чем вступать в многопоточное программирование).

Объекты и память по своей сути являются многопоточными в том смысле, что все потоки процесса могут обращаться к ним по своему усмотрению.

Таким образом, объекты не имеют ничего общего с потоками.

Тем не менее, код выполняется в потоке, и это поток, выполняемый кодом, в котором вы, вероятно, уже находитесь.

К сожалению, нет способа просто "поместить объект в другой поток", как вы выразились, вам нужно специально запустить поток и указать, какой код выполнить в этом потоке. Таким образом, объекты, используемые этим кодом, могут быть "сказаны" принадлежать этому потоку, хотя это искусственный лимит, который вы навязываете себе.

Таким образом, нет никакого способа сделать это:

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

Метод здесь будет выполняться в Thread 2. Единственный способ получить метод для выполнения в исходном потоке - это сотрудничество с исходным потоком и "попросить его" выполнить этот метод. Как вы это делаете, это зависит от ситуации и существует много способов сделать это.

Итак, суммируем то, что вы хотите: вы хотите создать новый поток и выполнить код в этом потоке.

Для этого просмотрите класс Thread.NET.

Но будьте осторожны: многопоточные приложения чрезвычайно сложно получить правильно, я бы не добавлял многопоточные возможности в программу, если только:

  • Это единственный способ получить от него больше производительности.
  • И вы знаете, что делаете.

Ответ 3

Все потоки процесса имеют одни и те же данные (игнорируя локальное хранилище потоков), поэтому нет необходимости явно переносить объекты между потоками.

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();
    }
}

Ответ 4

Все потоки могут видеть стек кучу, поэтому, если поток имеет ссылку на нужные вам объекты (например, передается через метод), тогда поток могут использовать эти объекты. Вот почему вы должны очень осторожно обращаться к объектам при многопоточности, поскольку два потока могут попытаться и одновременно изменить объект.

В .NET существует класс ThreadLocal<T>, который можно использовать для ограничения переменных для определенного потока: см. http://msdn.microsoft.com/en-us/library/dd642243.aspx и http://www.c-sharpcorner.com/UploadFile/ddoedens/UseThreadLocals11212005053901AM/UseThreadLocals.aspx

Ответ 5

Используйте ParameterizedThreadStart для передачи объекта в поток.

Ответ 6

"для последующего использования методов, которые он предоставляет.

Используя класс, содержащий метод для выполнения на новом потоке и другие данные и методы, вы можете получить доступ из своего потока к данным и методам из нового потока.

Но... если вы выполняете метод из класса, вы выполняете текущий поток.

Для выполнения метода в новом потоке требуется некоторая синхронизация Thread.

System.Windows.Forms.Control.BeginInvoke сделать это, поток управления ожидает получения запроса.

Класс WaitHandle может помочь вам.

Ответ 7

Извините, что дублировал предыдущую работу, но 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.";
}}}}

Ответ 8

Также как и в предыдущем ответе. Чтобы вернуться к проблеме, объекты и пространство памяти разделяются всеми потоками. Поэтому они всегда разделяются, но я предполагаю, что вы хотите сделать это безопасно и работать с результатами, созданными другим потоком.

Сначала попробуйте один из доверенных шаблонов С#. Асинхронные шаблоны  Существуют установленные шаблоны для работы, которые передают основные сообщения и данные между потоками. Обычно одна угроза завершается после вычисления результатов!

Жизненные угрозы: ничто не является доказательством дурака при переходе на асинхронный обмен данными о жизненных угрозах. Поэтому в основном держите его как можно проще, если вам нужно пройти этот маршрут и попробовать следовать известным шаблонам.

Итак, теперь я просто хочу объяснить, почему некоторые из известных паттеров имеют определенную структуру:

Eventargs: где вы создаете глубокую копию объектов перед его передачей. (Это не является надежным, поскольку некоторые ссылки могут по-прежнему использоваться совместно.) Передача результатов с базовыми типами, такими как int float и т.д. Они могут быть созданы на конструкторе и сделаны неизменными.

Атомные ключевые слова один из этих типов, или создавать мониторы и т.д. Придерживайтесь одного потока, читает другую запись.

Предполагая, что у вас есть сложные данные, которые вы хотели бы работать на двух потоках одновременно, совершенно разные способы решения этой проблемы, которые я еще не тестировал: Вы можете сохранить результаты в базе данных и позволить другому исполняемому файлу прочитать его. (Там блокировки происходят на уровне строк, но вы можете попробовать еще раз или изменить код SQL, и, по крайней мере, вы получите сообщения о взаимоблокировках, которые могут быть решены с хорошим дизайном, а не только с программным обеспечением!) Я бы сделал это, только если это действительно сделает смысл хранить данные в базе данных по другим причинам.

Другим способом, который помогает, является программирование F #. Объекты и все типы неизменяемы по умолчанию/Итак, ваши объекты, которые вы хотите разделить, должны иметь конструктор, и никакие методы не позволяют объекту получать изменения или базовые типы для увеличения. Поэтому вы их создаете, а потом они не меняются! Таким образом, после этого они не изменяются. Делает их более удобными для их блокировки и работы с ними. Не сходите с ума от этого в классах С#, потому что другие могут следовать этому "соглашению", и большинство таких вещей, как Списки, просто не были предназначены для неизменного в С# (только для чтения, это не то же самое, что и неизменяемое, const, но это очень ограничивает). Неизменяемость по сравнению с версией readonly

Ответ 9

Если метод, который вы запускаете в потоке, находится в настраиваемом классе, вы можете иметь члены этого класса для хранения параметров.

public class Foo
{
   object parameter1;
   object parameter2;

   public void ThreadMethod()
   {
       ...
   }
}