스레드에서 값을 반환합니까?


답변:


94

스레드에서 반환 값을 얻는 가장 쉬운 방법 중 하나는 클로저를 사용하는 것입니다. 스레드의 반환 값을 저장할 변수를 만든 다음 람다 식으로 캡처합니다. 작업자 스레드에서이 변수에 "반환"값을 할당 한 다음 해당 스레드가 종료되면 부모 스레드에서 사용할 수 있습니다.

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"; }다중 스레드 값 쓰기를 처리하는 것이 더 좋지 않을까요 ?
검사

4
@checksum :이 특정 경우에는 읽기 또는 쓰기가 value동시에 발생 하지 않기 때문에 불필요 합니다. 그러나 예, 자물쇠가 필요할 때 항상 염두에 두십시오.
Brian Gideon

기상! 훌륭하게 작동하며 허용되는 답변이어야합니다.
MerseyViking

34

스레드 생성 방법과 사용 가능한 .NET 버전에 따라 다릅니다.

.NET 2.0 이상 :

A) Thread개체를 직접 만들 수 있습니다 . 이 경우 "closure"를 사용할 수 있습니다. 변수를 선언하고 lambda-expression을 사용하여 캡처합니다.

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

B) 대리자를 사용하고 메서드 IAsyncResult에서 값을 반환 할 수 있습니다 EndInvoke().

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

C) BackgroundWorker수업 을 사용할 수 있습니다 . 이 경우 캡처 된 변수 (예 : Thread객체 포함)를 사용하거나 RunWorkerCompleted이벤트를 처리 할 수 있습니다 .

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부터는 Task Parallel LibraryTask클래스를 사용하여 스레드를 시작할 수 있습니다. 일반 클래스를 Task<TResult>사용하면 Result속성 에서 반환 값을 가져올 수 있습니다 .

//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부터는 속성 을 얻는 대신 async/ await키워드를 사용 하여 작업에서 직접 값을 반환 할 수도 있습니다 Result.

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

참고 : 위의 코드가 포함 된 메서드는 async키워드 로 표시됩니다 .

여러 가지 이유로 Task Parallel Library를 사용하는 것이 스레드 작업에 선호되는 방법입니다.


33

BackgroundWorker 접근 방식을 사용하고 결과를 e.Result에 반환합니다.

편집하다:

이것은 일반적으로 WinForms 및 WPF와 관련이 있지만 모든 유형의 .NET 응용 프로그램에서 사용할 수 있습니다. BackgroundWorker를 사용하는 콘솔 앱의 샘플 코드는 다음과 같습니다.

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

산출:

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 업데이트

아래 @Roger의 답변을 참조하십시오.

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

그는를 반환 Task<T>하고를 확인 하는 Task를 사용할 수 있다고 지적합니다 Task<T>.Result.


예, 그러나 WinForms 및 WPF에만 적용됩니다.
Henk Holterman

@Henk : 사실이 아닙니다. 방금 BackgroundWorker를 사용하는 간단한 콘솔 앱을 작성하여 확인했습니다. :-) 해당 코드로 게시물을 편집했습니다.
Eric J.

Eric, 언제 무슨 일이 발생하는지, 어떤 ThreadId에 대해 알아보기 위해 코드에 글을 써주세요. 예상대로되지 않을 수도 있습니다. (Completed는 주 스레드가 아니라 Dowork가 완료되기 전에 실행됩니다.) Bgw에는 MessagePump가 필요합니다.
Henk Holterman

@Henk : 당신은 반 오른쪽입니다. Completed는 BackgroundWorker와 동일한 스레드에서 실행되지만 DoWork가 완료된 후에 실행됩니다. 편집 된 답변의 출력을 참조하십시오.
Eric J.

2
경합 조건이 없습니다. 정확히 하나의 스레드가 변수를 설정하고 정확히 하나의 스레드가 변수를 읽기 때문에 정확한 설정 대 읽기 순서는 코드의 올바른 실행에 중요하지 않습니다 (즉, 종료 조건이 메인 스레드에서 발생할 수 있음). 스레드가 예약 된 순서에 따라 약간 더 빠르거나 늦었지만 어느 쪽이든 여전히 올바른 결과를 얻습니다).
Eric J.

21

스레드는 메소드가 아닙니다. 일반적으로 값을 "반환"하지 않습니다.

그러나 일부 처리 결과에서 값을 다시 가져 오려는 경우 다음과 같은 두 가지 주요 옵션이 있습니다.

  • 공유 데이터를 동기화하고 적절하게 설정할 수 있습니다.
  • 또한 어떤 형태의 콜백으로 데이터를 다시 전달할 수도 있습니다.

스레드를 만드는 방법, 사용하는 방법, 사용중인 언어 / 프레임 워크 / 도구에 따라 다릅니다.


15

내가 가장 좋아하는 클래스는 단 2 줄의 코드로 다른 스레드에서 모든 메서드를 실행합니다.

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

용법

    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는 starthework와 동일한 스레드에서 실행되지 않습니다.

매개 변수를받는 메소드의 경우 항상 클로저를 사용하거나 클래스를 확장 할 수 있습니다.


3
모두에게 명확하지 않습니다 ... stuffReturned ?, resultOfWork, PrintWorkComplete? 등
Lost_In_Library

14

다음은 대리자를 사용하는 간단한 예입니다.

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

Threading in C # 에는 스레딩에 대한 훌륭한 시리즈가 있습니다 .


9

위임 방식을 사용하기 만하면됩니다.

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

이제 다른 스레드에서 작동하는 Multiply 함수를 만듭니다.

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

3
이 대답이 "텍스트 파일에 저장하고 검색"하는 이유는 무엇입니까?
Jon

7

Thread 내에서 실행되는 메서드의 반환 값을 얻으려고 할 때이 스레드를 발견했습니다. 작동하는 솔루션을 게시 할 것이라고 생각했습니다.

이 솔루션은 클래스를 사용하여 실행할 메서드를 간접적으로 저장하고 반환 값을 저장합니다. 이 클래스는 모든 함수 및 반환 유형에 사용할 수 있습니다. 반환 값 형식을 사용하여 개체를 인스턴스화 한 다음 람다 (또는 대리자)를 통해 호출 할 함수를 전달하면됩니다.


C # 3.0 구현


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

이 코드를 사용하려면 Lambda (또는 대리자)를 사용할 수 있습니다. 다음은 람다를 사용하는 예입니다.

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 구현


VB.NET 2008을 사용하는 사람은 누구나 값을 반환하지 않는 메서드와 함께 람다를 사용할 수 없습니다. 이것은 ThreadedMethod클래스에 영향을 미치므로 ExecuteMethod함수의 값을 반환합니다. 이것은 아무것도 해치지 않습니다.

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

최신 .NET Framework에서는 Task를 사용하여 별도의 스레드에서 값을 반환 할 수 있습니다. 여기서 Result 속성은 작업이 완료 될 때까지 호출 스레드를 차단합니다.

  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;

자세한 내용은 http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx 를 참조하십시오 .


5

스레드를 시작하는 데 사용되는 C #의 ThreadStart 대리자는 반환 형식 'void'를 갖습니다.

스레드에서 '반환 값'을 얻으려면 공유 위치 (적절한 스레드 안전 방식)에 쓰고 스레드 실행이 완료되었을 때 읽어야합니다.


5

BackgroundWorker를 사용하지 않고 일반 스레드 만 사용하는 경우 이벤트를 발생시켜 다음과 같은 데이터를 반환 할 수 있습니다.

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

    }
}

귀하의 코드에서 사소한 세부 사항을 수정했습니다. 당신이 중단 된 것 같습니다 thread1_자신의 배선까지의에 대한 부분 AsyncCompletedEventHandler을 . 제 편집이 잘못 되었다면 무슨 일이 일어나고 있는지 이해하도록 도와주세요.
jp2code

1
@ jp2code 함수의 이름 thread1_Thread1Completed +=이기 thread1_Thread1Completed때문에 할 수 없으므로 할당 연산자의 왼쪽에 놓을 수 없습니다. 왼쪽 Thread1Completed +=은 이벤트이기 때문에 사용되므로 이벤트 핸들러를 추가하기 위해 할당 연산자의 왼쪽에 나타날 수 있습니다. 참조public event AsyncCompletedEventHandler Thread1Completed;
AaronLS 2015 년

나는 지금 그것을 본다. #region이전에 섹션 에서 해당 이벤트 처리기를 볼 수 없었던 이유를 모르겠습니다 . 나는 보았다. 정직한! :)
jp2code

2

스레드에는 실제로 반환 값이 없습니다. 그러나 대리자를 만드는 경우 BeginInvoke메서드 를 통해 비동기 적으로 호출 할 수 있습니다 . 이것은 스레드 풀 스레드에서 메소드를 실행합니다. 를 통한 호출과 같은 반환 값을 얻을 수 있습니다 EndInvoke.

예:

static int GetAnswer() {
   return 42;
}

...

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

GetAnswer스레드 풀 스레드에서 실행되며 완료되면 EndInvoke그림과 같이 답변을 검색 할 수 있습니다 .


2

BackgroundWorker에 윈도우 폼에 대한 개발을 할 때 좋다.

간단한 수업을 앞뒤로 전달하고 싶다고 가정 해 보겠습니다.

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

다음을 수행하는 짧은 수업을 작성했습니다.

  • 목록 만들기 또는 지우기
  • 루프 시작
  • 루프에서 목록에 대한 새 항목을 만듭니다.
  • 루프에서 스레드 생성
  • 루프에서 항목을 매개 변수로 스레드에 보냅니다.
  • 루프에서 스레드 시작
  • 루프에서 볼 목록에 스레드 추가
  • 루프 후 각 스레드를 결합하십시오.
  • 모든 조인이 완료되면 결과 표시

스레드 루틴 내부에서 :

  • 한 번에 하나의 스레드 만이 루틴에 들어갈 수 있도록 잠금을 호출합니다 (다른 스레드는 기다려야 함).
  • 항목에 대한 정보를 게시합니다.
  • 항목을 수정하십시오.
  • 스레드가 완료되면 데이터가 콘솔에 표시됩니다.

대리자를 추가하면 데이터를 기본 스레드에 직접 다시 게시하는 데 유용 할 수 있지만 일부 데이터 항목이 스레드로부터 안전하지 않은 경우 Invoke 를 사용해야 할 수 있습니다.

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

}

이를 테스트하려면 작은 콘솔 응용 프로그램을 만들고 Program.cs 파일 에 넣으십시오 .

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

}

다음은 이것으로 얻은 스크린 샷입니다.

콘솔 출력

내가 설명하려고했던 것을 다른 사람들이 이해할 수 있기를 바랍니다.

스레드 작업과 델리게이트 사용을 즐깁니다. 그들은 C #을 매우 재미있게 만듭니다.

부록 : VB 코더 용

위의 코드를 VB 콘솔 응용 프로그램으로 작성하는 데 무엇이 포함되어 있는지보고 싶었습니다. 변환에는 내가 예상하지 못한 몇 가지 사항이 포함되었으므로 VB에서 스레드하는 방법을 알고 싶은 사람들을 위해 여기에서이 스레드를 업데이트 할 것입니다.

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";
    }
}

제공된 예제가 잘못되었습니다. 당신은 그것이 당신을 위해 일한 행운을 얻었습니다. 다음 상황을 상상해보십시오 test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}. 이 경우 독립형 스레드는 returnValue변수에 새 값을 할당 할 시간이 없습니다 . 최후의 수단으로 스레드 참조를 저장 한 var standaloneThread = new Thread(()=> //...);다음 동기화 된 방식으로 시작할 수 standaloneThread.Start(); standaloneThread.Join();있습니다. 그러나 이것은 확실히 모범 사례가 아닙니다.
AlexMelw

1

간단한 해결책은 스레드에서 실행중인 함수에 ref로 매개 변수를 전달하고 스레드에서 해당 값을 변경하는 것입니다.

       // 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
        }

트레드에서 실행중인 함수를 변경할 수없는 경우 다른 함수를 래핑 할 수 있습니다.

 bool theirFunction(var someVar){
   return false;
}


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

반대표를 설명 해주세요. 이 패턴을 내 코드에서 사용하고 완벽하게 작동합니다.
CodeToad 2014

0

이 코드를 사용할 수 있습니다.

 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

저는 스레딩 전문가가 아니기 때문에 다음과 같이했습니다.

설정 파일을 만들고

새 스레드 내부 :

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

그런 다음 필요할 때마다 그 가치를 선택합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.