İş parçacığından bir değer mi döndürüyorsunuz?


Yanıtlar:


94

Bir iş parçacığından bir dönüş değeri almanın en kolay yollarından biri, kapanışları kullanmaktır. İş parçacığından dönüş değerini tutacak ve ardından onu bir lambda ifadesinde yakalayacak bir değişken oluşturun. Bu değişkene "dönüş" değerini işçi evresinden atayın ve sonra bu evre bittiğinde onu ana evreden kullanabilirsiniz.

void Main()
{
  object value = null; // Used to store the return value
  var thread = new Thread(
    () =>
    {
      value = "Hello World"; // Publish the return value
    });
  thread.Start();
  thread.Join();
  Console.WriteLine(value); // Use the return value here
}

3
lock(value) { value = "Hello world"; }Birden çok iş parçacığı değeri yazmayı ele almak daha iyi olmaz mıydı ?
checksum

4
@checksum: Bu özel durumda gereksizdir çünkü valueaynı anda hiçbir okuma veya yazma işlemi gerçekleşmez. Ancak, evet, bir kilit gerekli olduğunda her zaman dikkatli olun.
Brian Gideon

Harika fikir! Zekice çalışıyor ve kabul edilen cevap olmalı.
MerseyViking

34

İş parçacığını ve kullanılabilir .NET sürümünü nasıl oluşturmak istediğinize bağlıdır:

.NET 2.0+:

A) ThreadNesneyi doğrudan oluşturabilirsiniz . Bu durumda "closure" kullanabilirsiniz - değişken bildirebilir ve lambda-ifadesini kullanarak onu yakalayabilirsiniz:

object result = null;
Thread thread = new System.Threading.Thread(() => { 
    //Some work...
    result = 42; });
thread.Start();
thread.Join();
Console.WriteLine(result);

B) Temsilcileri kullanabilir ve yöntemden IAsyncResultdeğer döndürebilirsiniz EndInvoke():

delegate object MyFunc();
...
MyFunc x = new MyFunc(() => { 
    //Some work...
    return 42; });
IAsyncResult asyncResult = x.BeginInvoke(null, null);
object result = x.EndInvoke(asyncResult);

C) BackgroundWorkerSınıfı kullanabilirsiniz . Bu durumda yakalanan değişkeni ( Threadnesnede olduğu gibi ) kullanabilir veya RunWorkerCompletedolayı işleyebilirsiniz :

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
    //Some work...
    e.Result = 42;
};
worker.RunWorkerCompleted += (s, e) => {
    //e.Result "returned" from thread
    Console.WriteLine(e.Result);
};
worker.RunWorkerAsync();

.NET 4.0+:

.NET 4.0'dan başlayarak , iş parçacıklarınızı başlatmak için Görev Paralel Kitaplığı ve Tasksınıfı kullanabilirsiniz. Genel sınıf Task<TResult>, Resultözellikten dönüş değeri almanızı sağlar :

//Main thread will be blocked until task thread finishes
//(because of obtaining the value of the Result property)
int result = Task.Factory.StartNew(() => {
    //Some work...
    return 42;}).Result;

.NET 4.5+:

NET 4.5'ten başlayarak, özellik elde etmek yerine doğrudan görevden değer döndürmek için async/ awaitanahtar sözcüklerini de kullanabilirsiniz Result:

int result = await Task.Run(() => {
    //Some work...
    return 42; });

Not: Yukarıdaki kodu içeren yöntem asyncanahtar sözcük ile işaretlenmelidir .

Birçok nedenden dolayı, İş Parçacıklarıyla çalışmanın tercih edilen bir yolu Görev Paralel Kitaplığı'dır.


33

Ben kullanırım BackgroundWorker yaklaşım ve e.Result sonucu döndürür.

DÜZENLE:

Bu genellikle WinForms ve WPF ile ilişkilidir, ancak her tür .NET uygulaması tarafından kullanılabilir. BackgroundWorker'ı kullanan bir konsol uygulaması için örnek kod:

using System;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;

namespace BGWorker
{
    class Program
    {
        static bool done = false;

        static void Main(string[] args)
        {
            BackgroundWorker bg = new BackgroundWorker();
            bg.DoWork += new DoWorkEventHandler(bg_DoWork);
            bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
            bg.RunWorkerAsync();

            while (!done)
            {
                Console.WriteLine("Waiting in Main, tid " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(100);
            }
        }

        static void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Console.WriteLine("Completed, tid " + Thread.CurrentThread.ManagedThreadId);
            done = true;
        }

        static void bg_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Work Line: " + i + ", tid " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
            }
        }
    }
}

Çıktı:

Waiting in Main, tid 10
Work Line: 1, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 2, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 3, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 4, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Work Line: 5, tid 6
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Waiting in Main, tid 10
Completed, tid 6

2014 GÜNCELLEME

Aşağıdaki @ Roger'ın cevabına bakın.

https://stackoverflow.com/a/24916747/141172

A Task<T>ve check döndüren bir Task kullanabileceğinizi belirtir Task<T>.Result.


Evet, ancak yalnızca WinForms ve WPF için geçerlidir.
Henk Holterman

@Henk: Doğru değil. Sadece emin olmak için BackgroundWorker'ı kullanan basit bir konsol uygulaması yazdım :-) Gönderimi bu kodla düzenledim.
Eric J.

Eric, ne zaman ve hangi ThreadId olduğunu görmek için kodunuza bazı yazılar ekleyin. Beklediğiniz gibi gitmeyebilir. (Completed, Dowork bitmeden çalışacaktır ve Main thread üzerinde çalışmayacaktır). Bgw'nin bir MessagePump'a ihtiyacı var.
Henk Holterman

@Henk: Yarı haklısın. Tamamlanan, BackgroundWorker ile aynı iş parçacığı üzerinde çalışır, ancak DoWork tamamlandıktan sonra çalışır. Düzenlenmiş yanıtta çıktıya bakın.
Eric J.

2
Yarış koşulu yoktur, çünkü tam olarak bir iş parçacığı değişkeni belirler ve tam olarak bir iş parçacığı onu okur ve küme ile okuma arasındaki kesin sıralama, kodun doğru yürütülmesi açısından önemli değildir (yani, ana iş parçacığında sonlandırma koşulu oluşabilir Konuların planlandığı sıraya bağlı olarak biraz daha erken veya sonra, ancak her iki durumda da yine de doğru bir sonuç alırsınız).
Eric J.

21

Bir iş parçacığı bir yöntem değildir - normalde bir değer "döndürmezsiniz".

Ancak, bazı işlemlerin sonuçlarından geri bir değer almaya çalışıyorsanız, birçok seçeneğiniz vardır, bunlardan ikisi:

  • Paylaşılan bir veri parçasını senkronize edebilir ve uygun şekilde ayarlayabilirsiniz.
  • Verileri bir tür geri arama şeklinde de geri iletebilirsiniz.

Bu gerçekten iş parçacığını nasıl oluşturduğunuza ve onu nasıl kullanmak istediğinize ve ayrıca kullandığınız dile / çerçeveye / araçlara bağlıdır.


15

En sevdiğim sınıf, herhangi bir yöntemi başka bir iş parçacığında yalnızca 2 satır kodla çalıştırır.

class ThreadedExecuter<T> where T : class
{
    public delegate void CallBackDelegate(T returnValue);
    public delegate T MethodDelegate();
    private CallBackDelegate callback;
    private MethodDelegate method;

    private Thread t;

    public ThreadedExecuter(MethodDelegate method, CallBackDelegate callback)
    {
        this.method = method;
        this.callback = callback;
        t = new Thread(this.Process);
    }
    public void Start()
    {
        t.Start();
    }
    public void Abort()
    {
        t.Abort();
        callback(null); //can be left out depending on your needs
    }
    private void Process()
    {
        T stuffReturned = method();
        callback(stuffReturned);
    }
}

kullanım

    void startthework()
    {
        ThreadedExecuter<string> executer = new ThreadedExecuter<string>(someLongFunction, longFunctionComplete);
        executer.Start();
    }
    string someLongFunction()
    {
        while(!workComplete)
            WorkWork();
        return resultOfWork;
    }
    void longFunctionComplete(string s)
    {
        PrintWorkComplete(s);
    }

LongFunctionComplete'in yıldız işi ile aynı iş parçacığı üzerinde çalışmayacağına dikkat edin.

Parametreleri alan yöntemler için her zaman kapanışları kullanabilir veya sınıfı genişletebilirsiniz.


3
Herkes için net değil ... geri dönen şeyler ?, resultOfWork, PrintWorkComplete? vb.
Lost_In_Library

14

İşte bir temsilci kullanan basit bir örnek ...

void Main()
{
   DoIt d1 = Doer.DoThatThang;
   DoIt d2 = Doer.DoThatThang;

   IAsyncResult r1 = d1.BeginInvoke( 5, null, null );
   IAsyncResult r2 = d2.BeginInvoke( 10, null, null );

   Thread.Sleep( 1000 );

   var s1 = d1.EndInvoke( r1 );
   var s2 = d2.EndInvoke( r2 );

   s1.Dump(); // You told me 5
   s2.Dump(); // You told me 10
}

public delegate string DoIt( int x );

public class Doer
{
  public static string DoThatThang( int x  )
  {
    return "You told me " + x.ToString();
  }
}

C # ' da Threading'de diş açma konusunda müthiş bir dizi var .


9

Temsilci yaklaşımını kullanmanız yeterlidir.

int val;
Thread thread = new Thread(() => { val = Multiply(1, 2); });
thread.Start();

Şimdi başka bir iş parçacığı üzerinde çalışacak Çarpma işlevini yapın:

int Multiply(int x, int y)
{
    return x * y;
}

3
Bu yanıt neden aşağıda "bir metin dosyasına kaydet ve geri al"?
Jon

7

Bir İş Parçacığı içinde çalıştırılan bir yöntemin dönüş değerini elde etmeye çalışırken de bu iş parçacığına rastladım. İşe yarayan çözümümü yayınlayacağımı düşündüm.

Bu çözüm, hem yürütülecek yöntemi (dolaylı olarak) depolamak için bir sınıf kullanır hem de dönen değeri depolar. Sınıf, herhangi bir işlev ve herhangi bir dönüş türü için kullanılabilir. Yalnızca dönüş değeri türünü kullanarak nesneyi başlatırsınız ve ardından işlevi bir lambda (veya temsilci) aracılığıyla çağırmak için iletirsiniz.


C # 3.0 Uygulaması


public class ThreadedMethod<T>
{

    private T mResult;
    public T Result 
    {
        get { return mResult; }
        private set { mResult = value; }
    }

    public ThreadedMethod()
    {
    }

    //If supporting .net 3.5
    public void ExecuteMethod(Func<T> func)
    {
        Result = func.Invoke();
    }

    //If supporting only 2.0 use this and 
    //comment out the other overload
    public void ExecuteMethod(Delegate d)
    {
        Result = (T)d.DynamicInvoke();
    }
}

Bu kodu kullanmak için bir Lambda (veya bir temsilci) kullanabilirsiniz. İşte lambdas kullanan örnek:

ThreadedMethod<bool> threadedMethod = new ThreadedMethod<bool>();
Thread workerThread = new Thread((unused) => 
                            threadedMethod.ExecuteMethod(() => 
                                SomeMethod()));
workerThread.Start();
workerThread.Join();
if (threadedMethod.Result == false) 
{
    //do something about it...
}

VB.NET 2008 Uygulaması


VB.NET 2008 kullanan hiç kimse, değer içermeyen döndürme yöntemleriyle lambdaları kullanamaz. Bu ThreadedMethodsınıfı etkiler , bu nedenle ExecuteMethodfonksiyonun değerini döndürürüz. Bu hiçbir şeye zarar vermez.

Public Class ThreadedMethod(Of T)

    Private mResult As T
    Public Property Result() As T
        Get
            Return mResult
        End Get
        Private Set(ByVal value As T)
            mResult = value
        End Set
    End Property

    Sub New()
    End Sub

    'If supporting .net 3.5'
    Function ExecuteMethod(ByVal func As Func(Of T)) As T
        Result = func.Invoke()
        Return Result
    End Function

    'If supporting only 2.0 use this and' 
    'comment out the other overload'
    Function ExecuteMethod(ByVal d As [Delegate]) As T
        Result = DirectCast(d.DynamicInvoke(), T)
        Return Result
    End Function

End Class

7

En son .NET Framework ile, bir Görev kullanarak ayrı bir iş parçacığından bir değer döndürmek mümkündür; burada Sonuç özelliği, görev bitene kadar çağıran iş parçacığını engeller:

  Task<MyClass> task = Task<MyClass>.Factory.StartNew(() =>
  {
      string s = "my message";
      double d = 3.14159;
      return new MyClass { Name = s, Number = d };
  });
  MyClass test = task.Result;

Ayrıntılar için lütfen bkz. Http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx


5

ThreadStart delegeleri C # 'da evreleri başlatmak için kullanılan' void 'dönüş tipine sahip.

Bir iş parçacığından bir 'dönüş değeri' almak istiyorsanız, paylaşılan bir konuma (uygun iş parçacığı güvenli bir şekilde) yazmalı ve iş parçacığı yürütülmeyi tamamladığında oradan okumalısınız.


5

Bir BackgroundWorker kullanmak istemiyorsanız ve yalnızca normal bir İş Parçacığı kullanıyorsanız, bunun gibi verileri döndürmek için bir olay başlatabilirsiniz:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadWithDataReturnExample
{
    public partial class Form1 : Form
    {
        private Thread thread1 = null;

        public Form1()
        {
            InitializeComponent();

            thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
            Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            thread1.Start();
            //Alternatively, you could pass some object
            //in such as Start(someObject);
            //With apprioriate locking, or protocol where
            //no other threads access the object until
            //an event signals when the thread is complete,
            //any other class with a reference to the object 
            //would be able to access that data.
            //But instead, I'm going to use AsyncCompletedEventArgs 
            //in an event that signals completion
        }

        void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
        {
            if (this.InvokeRequired)
            {//marshal the call if we are not on the GUI thread                
                BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
                  new object[] { sender, e });
            }
            else
            {
                //display error if error occurred
                //if no error occurred, process data
                if (e.Error == null)
                {//then success

                    MessageBox.Show("Worker thread completed successfully");
                    DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
                    MessageBox.Show("Your data my lord: " + someData.someProperty);

                }
                else//error
                {
                    MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
                }
            }
        }

        #region I would actually move all of this into it's own class
            private void threadEntryPoint()
            {
                //do a bunch of stuff

                //when you are done:
                //initialize object with data that you want to return
                DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
                dataYouWantToReturn.someProperty = "more data";

                //signal completion by firing an event
                OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
            }

            /// <summary>
            /// Occurs when processing has finished or an error occurred.
            /// </summary>
            public event AsyncCompletedEventHandler Thread1Completed;
            protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
            {
                //copy locally
                AsyncCompletedEventHandler handler = Thread1Completed;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        #endregion

    }
}

Kodunuzdaki küçük bir ayrıntıyı düzelttim. Görünüşe göre AsyncCompletedEventHandler'ınthread1_ kablolamasında kısmı bırakmışsınız . Düzenlemem hatalıysa, lütfen orada neler olduğunu anlamama yardım edin.
jp2code

1
@ jp2code Bunu yapamazsınız thread1_Thread1Completed +=çünkü thread1_Thread1Completedbir işlevin adıdır, bu yüzden onu bir atama operatörünün sol tarafına koyamazsınız. Sol taraf Thread1Completed +=, bu bir olay olduğu için kullanılır, böylece olay işleyicileri eklemek için atama operatörünün sol tarafında görünebilir. Bkzpublic event AsyncCompletedEventHandler Thread1Completed;
AaronLS

Şimdi anlıyorum. Bu olay işleyicisini daha #regionönce sizin bölümünüzde neden göremediğimi bilmiyorum . Baktım. Dürüst! :)
jp2code

2

İpliklerin gerçekten dönüş değerleri yoktur. Ancak, bir temsilci oluşturursanız, bunu BeginInvokeyöntem aracılığıyla eşzamansız olarak çağırabilirsiniz . Bu, yöntemi bir iş parçacığı havuzu iş parçacığında yürütür. Call via gibi herhangi bir dönüş değerini alabilirsiniz EndInvoke.

Misal:

static int GetAnswer() {
   return 42;
}

...

Func<int> method = GetAnswer;
var res = method.BeginInvoke(null, null); // provide args as needed
var answer = method.EndInvoke(res);

GetAnsweriş parçacığı havuzu iş parçacığı üzerinde çalıştırılır ve tamamlandığında yanıtı EndInvokegösterildiği gibi aracılığıyla alabilirsiniz .


2

BackgroundWorker Windows Forms geliştirirken güzel.

Basit bir dersi ileri geri geçirmek istediğinizi varsayalım:

class Anything {
    // Number and Text are for instructional purposes only
    public int Number { get; set; }
    public string Text { get; set; }
    // Data can be any object - even another class
    public object Data { get; set; }
}

Aşağıdakileri yapan kısa bir sınıf yazdım:

  • Liste Oluşturun veya Silin
  • Bir döngü başlatın
  • Döngüde, liste için yeni bir öğe oluşturun
  • Döngüde bir iş parçacığı oluşturun
  • Döngüde, öğeyi iş parçacığına bir parametre olarak gönderin
  • Döngüde, iş parçacığını başlatın
  • Döngüde, izlemek için listeye ileti dizisi ekleyin
  • Döngüden sonra, her iş parçacığını birleştirin
  • Tüm birleştirmeler tamamlandıktan sonra sonuçları görüntüleyin

İplik rutininin içinden:

  • Çağrı kilidi, bu rutine bir seferde yalnızca 1 iş parçacığı girebilir (diğerlerinin beklemesi gerekir)
  • Öğe hakkında bilgi gönderin.
  • Öğeyi değiştirin.
  • İş parçacığı tamamlandığında veriler konsolda görüntülenir.

Temsilci eklemek , verilerinizi doğrudan ana iş parçacığınıza göndermek için yararlı olabilir, ancak bazı veri öğeleri iş parçacığı güvenli değilse Invoke'u kullanmanız gerekebilir .

class AnyTask {

    private object m_lock;

    public AnyTask() {
        m_lock = new object();
    }
    // Something to use the delegate
    public event MainDelegate OnUpdate;

    public void Test_Function(int count) {
        var list = new List<Thread>(count);
        for (var i = 0; i < count; i++) {
            var thread = new Thread(new ParameterizedThreadStart(Thread_Task));
            var item = new Anything() {
                Number = i,
                Text = String.Format("Test_Function #{0}", i)
            };
            thread.Start(item);
            list.Add(thread);
        }
        foreach (var thread in list) {
            thread.Join();
        }
    }

    private void MainUpdate(Anything item, bool original) {
        if (OnUpdate != null) {
            OnUpdate(item, original);
        }
    }

    private void Thread_Task(object parameter) {
        lock (m_lock) {
            var item = (Anything)parameter;
            MainUpdate(item, true);
            item.Text = String.Format("{0}; Thread_Task #{1}", item.Text, item.Number);
            item.Number = 0;
            MainUpdate(item, false);
        }
    }

}

Bunu test etmek için küçük bir Konsol Uygulaması oluşturun ve bunu Program.cs dosyasına koyun :

// A delegate makes life simpler
delegate void MainDelegate(Anything sender, bool original);

class Program {

    private const int COUNT = 15;
    private static List<Anything> m_list;

    static void Main(string[] args) {
        m_list = new List<Anything>(COUNT);
        var obj = new AnyTask();
        obj.OnUpdate += new MainDelegate(ThreadMessages);
        obj.Test_Function(COUNT);
        Console.WriteLine();
        foreach (var item in m_list) {
            Console.WriteLine("[Complete]:" + item.Text);
        }
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    private static void ThreadMessages(Anything item, bool original) {
        if (original) {
            Console.WriteLine("[main method]:" + item.Text);
        } else {
            m_list.Add(item);
        }
    }

}

İşte bununla elde ettiğim şeyin bir ekran görüntüsü:

Konsol Çıkışı

Umarım başkaları açıklamaya çalıştığımı anlayabilir.

Konular üzerinde çalışmaktan ve temsilciler kullanmaktan zevk alıyorum. C # 'ı çok eğlenceli hale getiriyorlar.

Ek: VB Kodlayıcılar için

Yukarıdaki kodu bir VB Konsol Uygulaması olarak yazarken nelerin dahil olduğunu görmek istedim. Dönüşüm beklemediğim birkaç şeyi içeriyordu, bu yüzden VB'de nasıl işleneceğini bilmek isteyenler için bu konuyu burada güncelleyeceğim.

Imports System.Threading

Delegate Sub MainDelegate(sender As Anything, original As Boolean)

Class Main

    Private Const COUNT As Integer = 15
    Private Shared m_list As List(Of Anything)

    Public Shared Sub Main(args As String())
        m_list = New List(Of Anything)(COUNT)
        Dim obj As New AnyTask()
        AddHandler obj.OnUpdate, New MainDelegate(AddressOf ThreadMessages)
        obj.Test_Function(COUNT)
        Console.WriteLine()
        For Each item As Anything In m_list
            Console.WriteLine("[Complete]:" + item.Text)
        Next
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub

    Private Shared Sub ThreadMessages(item As Anything, original As Boolean)
        If original Then
            Console.WriteLine("[main method]:" + item.Text)
        Else
            m_list.Add(item)
        End If
    End Sub

End Class

Class AnyTask

    Private m_lock As Object

    Public Sub New()
        m_lock = New Object()
    End Sub
    ' Something to use the delegate
    Public Event OnUpdate As MainDelegate

    Public Sub Test_Function(count As Integer)
        Dim list As New List(Of Thread)(count)
        For i As Int32 = 0 To count - 1
            Dim thread As New Thread(New ParameterizedThreadStart(AddressOf Thread_Task))
            Dim item As New Anything()
            item.Number = i
            item.Text = String.Format("Test_Function #{0}", i)
            thread.Start(item)
            list.Add(thread)
        Next
        For Each thread As Thread In list
            thread.Join()
        Next
    End Sub

    Private Sub MainUpdate(item As Anything, original As Boolean)
        RaiseEvent OnUpdate(item, original)
    End Sub

    Private Sub Thread_Task(parameter As Object)
        SyncLock m_lock
            Dim item As Anything = DirectCast(parameter, Anything)
            MainUpdate(item, True)
            item.Text = [String].Format("{0}; Thread_Task #{1}", item.Text, item.Number)
            item.Number = 0
            MainUpdate(item, False)
        End SyncLock
    End Sub

End Class


Class Anything
    ' Number and Text are for instructional purposes only
    Public Property Number() As Integer
        Get
            Return m_Number
        End Get
        Set(value As Integer)
            m_Number = value
        End Set
    End Property
    Private m_Number As Integer
    Public Property Text() As String
        Get
            Return m_Text
        End Get
        Set(value As String)
            m_Text = value
        End Set
    End Property
    Private m_Text As String
    ' Data can be anything or another class
    Public Property Data() As Object
        Get
            Return m_Data
        End Get
        Set(value As Object)
            m_Data = value
        End Set
    End Property
    Private m_Data As Object
End Class

1
class Program
{
    static void Main(string[] args)
    {
        string returnValue = null;
       new Thread(
          () =>
          {
              returnValue =test() ; 
          }).Start();
        Console.WriteLine(returnValue);
        Console.ReadKey();
    }

    public static string test()
    {
        return "Returning From Thread called method";
    }
}

Verilen örnek yanlış, sizin için çalıştığı için şanslısınız. Aşağıdaki durumu hayal edin test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}. Bu durumda bağımsız iş parçacığı, returnValuedeğişkene yeni bir değer atamak için zamana sahip olmayacaktır . Son çare olarak, bir iş parçacığı referansı kaydedebilir var standaloneThread = new Thread(()=> //...);ve bundan sonra onu senkronize bir şekilde başlatabilirsiniz standaloneThread.Start(); standaloneThread.Join();. Ancak bu kesinlikle en iyi uygulama değildir.
AlexMelw

1

Basit bir çözüm, evre içinde çalışan işleve ref ile bir parametre iletmek ve iş parçacığı içindeki değerini değiştirmektir.

       // create a list of threads
        List<Thread> threads = new List<Thread>();


        //declare the ref params
        bool is1 = false;
        bool is2 = false;

        threads.Add(new Thread(() => myFunction(someVar, ref is1)));
        threads.Add(new Thread(() => myFunction(someVar, ref is2)));

        threads.ForEach(x => x.Start());

        // wait for threads to finish
        threads.ForEach(x => x.Join());

        //check the ref params
        if (!is1)
        {
          //do something
        }

        if (!is2)
        {
           //do somethign else
        }

Lastik sırtında çalışan işlevi değiştiremezseniz, onu başka bir işleve sarabilirsiniz:

 bool theirFunction(var someVar){
   return false;
}


 void myFunction(var someVar ref bool result){
  result = theirFunction(myVar);
 }

lütfen olumsuz oyu açıklayın. Bu kalıbı kendi kodumda kullanıyorum ve mükemmel çalışıyor.
CodeToad

0

Bu Kodu kullanabilir:

 private Object MyThread(Object Data)
      {
        Object response = null;
        Thread newThread = new Thread(() =>
        {
            response = MyFunction(Data);
            //MyFunction Is Function that you Define
        });
        newThread.Start();
        newThread.Join();
        return response;
      }

-1

Diş açma konusunda uzman değilim, bu yüzden böyle yaptım:

Bir Ayarlar dosyası oluşturdum ve

Yeni ileti dizisinin içinde:

Setting.Default.ValueToBeSaved;
Setting.Default.Save();

Sonra ihtiyacım olduğu zaman bu değeri alırım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.