문제

두 개의 스레드가있는 응용 프로그램이 있습니다.

소켓을 사용하여 데이터를 캡처하고 DataTables를 업데이트하는 첫 번째 (기본 스레드)

두 번째는 데이터 레이스를 데이터베이스에 삽입합니다.

응용 프로그램은 잘 작동하지만 닫히면 메인 스레드가 데이터를 읽고 두 번째 스레드에서 호출 중 Abort 메소드를 완료하여 데이터베이스에 삽입 될 수 있으며 이는 일관되지 않은 데이터로 이어집니다.

현재 "삽입 중 낙태"를 극복하기 위해 다음 솔루션을 사용하고 있습니다.

편집 : 강력한 답변 후 코드를 변경했습니다.

void MainThread()
{
     while(Read())
     {
        //Read Data through socket
        try
        {
           //Wait on Mutex1
           //Update Tables
        }
        finally
        {
          //Release Mutex1
        }
     }
   _isrunning = false;
   _secondThread.Join();
}
void SecondThread()
{
     while(_isrunning)
     {
        try
        {
           //Wait on Mutex1
           //Insert Tables into Database using transactions
        }
        finally
        {
           //Release Mutex1           
        }
     }
}
도움이 되었습니까?

해결책

"Call Abort 메소드"를 가정하면 Thread.Abort를 사용하여 스레드를 중단하는 것을 의미합니다. 그렇게하지 마십시오.

당신은 앱을 효과적으로 충돌시키고 있습니다. 모니터 로이 작업을 수행하는 더 깨끗한 방법이 있습니다.

그럼에도 불구하고 앱이 충돌 할 때 DB에서 일관성이없는 데이터를 얻지 않아야합니다. 속성.

매우 중요한 편집당신은 다음과 같이 말했습니다 : 당신은 성능상의 이유로 트랜잭션을 사용하지 않고 대신 뮤텍스를 사용합니다. 이것은 잘못된 꽤 많은 수준에서. 첫째, 트랜잭션은 특정 작업을 더 빨리 만들 수 있습니다. 예를 들어 10 행을 테이블에 삽입하려고 시도하고 트랜잭션 내에서 다시 시도하면 트랜잭션 버전이 더 빠릅니다. 둘째, 앱이 충돌하면 어떻게됩니까? DB가 손상 되었습니까? 앱의 여러 인스턴스가 실행되면 어떻게됩니까? 아니면 쿼리 분석기에서 DB에 대해 보고서를 실행하는 동안?

다른 팁

두 스레드가 배경 스레드로 표시되지 않는 한, 앱은 두 스레드가 종료 될 때까지 계속 실행됩니다. 따라서 실제로, 당신이해야 할 일은 각 스레드를 개별적으로 깨끗하게 빠져 나가는 것입니다. 데이터베이스에 쓰는 스레드의 경우, 이는 생산자/소비자 대기열을 소진하고 깃발을 종료하는 것을 의미 할 수 있습니다.

적합한 생산자/소비자 대기열을 보여주었습니다 여기 - 근로자는 다음과 같습니다.

void WriterLoop() {
    SomeWorkItem item; // could be a `DataTable` or similar
    while(queue.TryDequeue(out item)) {
        // process item
    }
    // queue is empty and has been closed; all done, so exit...
}

다음은 전체 예입니다 SizeQueue<> - 독자가 될 때까지 프로세스가 종료되지 않습니다. 그리고 작가는 깨끗하게 빠져 나갔다. 대기열을 배수하지 않아도되면 (예 : 더 빨리 종료하고 보류중인 작업을 잊어 버리려면), 여분의 (휘발성) 깃발을 어딘가에 추가하십시오.

static class Program {
    static void Write(object message) {
        Console.WriteLine(Thread.CurrentThread.Name + ": " + message);
    }
    static void Main() {
        Thread.CurrentThread.Name = "Reader";
        Thread writer = new Thread(WriterLoop);
        writer.Name = "Writer";
        var queue = new SizeQueue<int>(100);
        writer.Start(queue);
        // reader loop - note this can run parallel
        // to the writer
        for (int i = 0; i < 100; i++) {
            if (i % 10 == 9) Write(i);
            queue.Enqueue(i);
            Thread.Sleep(5); // pretend it takes time
        }
        queue.Close();
        Write("exiting");
    }
    static void WriterLoop(object state) {
        var queue = (SizeQueue<int>)state;
        int i;
        while (queue.TryDequeue(out i)) {
            if(i%10==9) Write(i);
            Thread.Sleep(10); // pretend it takes time
        }
        Write("exiting");
    }
}

뮤 테스 대기에는 타임 아웃이 필요합니다. 각 스레드의 외부 루프는 '지금 닫으십시오'플래그를 확인할 수 있습니다. 종료하려면 각 스레드의 '지금 닫으십시오'플래그를 설정 한 다음 '조인'을 사용하여 각 스레드가 완료 될 때까지 기다립니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top