2012-05-10 3 views
1

다른 스레드 생성 :예외 내가 최근에이 코드를 본 적이

static List<Thread> list = new List<Thread>(); 

static void Main(string[] args) 
{ 
    var lines = File.ReadAllLines(args[0]); 

    foreach (var line in lines) 
    { 
     StartThread(line); 
    } 

    Console.WriteLine("JOIN"); 

    foreach (Thread thread in list) 
    { 
     thread.Join(); 
    } 

    Console.WriteLine("END"); 
    Console.ReadKey(); 
} 

static void Upsert(object o) 
{ 
    var args = o.ToString().Split(','); 

    try 
    { 
     using (var con = new SqlConnection(Settings.Default.ConnString)) 
     { 
      var cmd = new SqlCommand 
          { 
           Connection = con, 
           CommandText = "INSERT INTO Accounts VALUES(@p1, @p2, @p3, @p4, @p5)" 
          }; 

      for (var index = 0; index < args.Length; index++) 
      { 
       cmd.Parameters.AddWithValue(@"@p" + (index + 1), args[index]); 
      } 

      try 
      { 
       con.Open(); 

       cmd.ExecuteNonQuery(); 

       Console.WriteLine("INSERTED"); 
      } 
      catch (SqlException e) 
      { 
       switch (e.Number) 
       { 
        case 2627: 
         cmd.CommandText = 
          "UPDATE Accounts SET [email protected], [email protected], [email protected], [email protected] WHERE ID = @p1"; 
         cmd.ExecuteNonQuery(); 
         Console.WriteLine("UPDATED"); 
         break; 
        case 1205: 
         StartThread(o); // On exception isn't some Thread handling should happen? 
         break; 
       } 
      } 
     } 
    } 
} 

private static void StartThread(object o) 
{ 
    // Is it correct to add another thread to the list again? when exception happens? What about the thread that was running 
    var t = new Thread(Upsert) 
    { 
     Priority = ThreadPriority.Highest, 
     IsBackground = true 
    }; 
    list.Add(t); 
    t.Start(o); 

    Console.WriteLine("NEW THREAD STARTED"); 
} 

내가 스레딩에 이렇게 강한 아니에요을, 나는 오류 1205가 발생할 수있는 경우 specificaly 그 코드에 대해 궁금하고 동일한 방법으로 다른 스레드를 다시 실행하여 스레드 목록에 한 번 더 추가하십시오. 이전에 예외가 발생한 스레드에 대한 검사가 끝나고 중단되어야합니다. 그런 다음 목록에서 제거하고 새 목록을 추가하십시오.

귀하의 기여가 정말 도움이됩니다.

감사합니다.

+0

처음으로이 코드를 보았습니다. http : // ayende.co.kr/blog/131073/memorable-code 코드에있는 많은 내용에 대한 의견이 많습니다. –

답변

2

이 코드에는 몇 가지 문제점이 있습니다.

  • list에 대한 액세스는 어떤 방식으로도 동기화되지 않습니다. 가입 메인 스레드와 새 스레드 사이의 경쟁 1205

이 코드를 스크랩하고 당신을 위해 upsert을 수행하는 저장 프로 시저를 만들 것이다 오류가 발생한 후 생성되는이 있습니다

  • . 이러한 상황은 서버 측에서 다루기가 훨씬 쉽습니다. 또한, 나는 어쨌든이 상황에 대한 멀티 쓰레딩에 대한 전체적인 생각을별로 좋아하지 않습니다.

    최대 속도를 원할 경우 C# 코드를 통해 파일을 읽고 구문 분석하여 개별 필드로 나눕니다. 그런 다음 SqlBulkCopy을 사용하여 임시로 모든 기록을 한 번에 임시 착륙 구역 테이블에 버려야합니다. 마지막으로 저장 프로 시저를 호출하여 임시 방문 영역의 레코드를 적절한 프로덕션 테이블로 전송합니다. 이 모든 작업자 스레드를 사용하지 않고 수행 할 수 있으며 훨씬 빠릅니다.

    업데이트 : 당신이 CountdownEvent을 사용하는 경우

    코드는 쉽게 해결할 수 있습니다. 스레드 목록을 완전히 처칭하고 모든 스레드에서 Join을 호출하는 대신 대기를 수행하기 위해 CountdownEvent을 인스턴스화하십시오.

    static CountdownEvent complete = new CountdownEvent(1); 
    
    static void Main(string[] args) 
    { 
        var lines = File.ReadAllLines(args[0]); 
    
        foreach (var line in lines) 
        { 
         StartThread(line); 
        } 
    
        Console.WriteLine("JOIN"); 
    
        complete.Signal(); 
        complete.Wait(); 
    
        Console.WriteLine("END"); 
        Console.ReadKey(); 
    } 
    

    그런 다음 StartThread을 이와 같이 변경하십시오.

    private static void StartThread(object o) 
    { 
        complete.AddCount(); 
        var t = new Thread(
        () => 
         { 
         try 
         { 
          Upsert(o); 
         } 
         finally 
         { 
          complete.Signal(); 
         } 
         }); 
        t.Priority = ThreadPriority.Highest; 
        t.IsBackground = true; 
        t.Start(); 
        Console.WriteLine("NEW THREAD STARTED"); 
    } 
    

    그래서 나는 그것뿐만 아니라 노동자 것처럼 메인 스레드를 처리하는 원하기 때문에 나는 CoundownEvent 1 카운트를 초기화하고있는 중이 야. 이렇게하면 주 스레드가 다른 스레드를 모두 회전하기 전에 작업자 중 하나가 완료되면 발생할 수있는 미묘한 경쟁 조건이 수정됩니다. 새 스레드를 시작할 때마다 AddCount이라고 부르며 스레드가 완료되면 Signal이라고합니다. 물론 주 스레드는 Wait을 호출하여 모든 것을 기다립니다.

    코드의 구조를 조금 더 변경하려면 아마도 Task을 통해 작업을 사용했을 것이며 오류 1205가 발생하면 하위 작업을 생성하고 TaskCreationOptions.AttachedToParent을 통해 부모에게 연결했을 것입니다. 그러나 그것은 좀 더 중요한 변화를 요구했을 것이며, 최소한의 변화를 유지하려고했습니다.

  • +0

    의견을 보내 주셔서 감사합니다. 그러나 누군가가 클라이언트 쪽에서 현재 스레드 조작을 도울 수 있으면 좋겠다. 어디에서 추천 한 변경 사항에 대해 데이터베이스에 액세스 할 권한이 없다고 가정 해 보겠습니다. –

    +0

    답을 업데이트했습니다. –

    +0

    당신은 핵폭탄을 던졌습니다. 너 락 : –

    관련 문제