문제의 역사:
스레드 작업 지원은 Perl 5.005에서 도입되었으나, 언어 구현의 특성으로 인해 오랫동안 실험적이었고 많은 버그와 제한 사항이 동반되었습니다. Perl 5.8부터 threads(및 threads::shared) 모듈은 더 심각한 작업을 위한 충분히 안정적으로 되었습니다. 그러나 Perl의 스레드 모델은 다른 많은 프로그래밍 언어와 크게 다릅니다. 각 스레드는 모든 변수의 복사본을 얻으며, 오직 명시적으로 선언된 구조체만이 threads::shared를 통해 공유 접근이 가능합니다.
문제:
"일반" 변수는 copy-on-write 세멘틱 때문에 스레드 간에 보이지 않습니다. threads::shared 없이 데이터를 분배하려고 하면 상태가 비동기화됩니다. 잠금을 부적절하게 사용할 경우 경쟁 상태, 교착 상태 또는 일관되지 않은 변경의 위험이 있습니다.
해결:
변수를 공유하기 위해서는 use threads::shared를 통해 공유 변수를 선언하십시오. 여러 스레드가 동시에 읽기/쓰기를 하는 경우 lock을 통해 공유 데이터에 대한 접근을 차단하십시오. 스레드의 생명 주기를 관리하기 위해 join/detach 메서드를 사용하십시오. 복잡한 구조의 경우 각 요소를 개별적으로 shared로 선언하십시오. "상위 수준"만으로는 완전한 스레드 안전성을 보장하지 않습니다.
코드 예시:
use threads; use threads::shared; my $counter :shared = 0; my @threads; for (1..10) { push @threads, threads->create(sub { for (1..1000) { lock($counter); ++$counter; } }); } $_->join() for @threads; print "Counter: $counter ";
핵심 특징:
:shared는 추가적인 lock 없이 스레드 안전성을 제공합니까?
아니요. :shared 속성은 스레드 간에 변수에 대한 접근을 제공하지만, 변경 사항(예: ++ 또는 --)은 원자적이지 않습니다. 각 중요 섹션에 대해 lock이 필요합니다.
하나의 :shared 지시문으로 스레드 간에 복잡한 구조(해시의 배열)를 공유할 수 있습니까?
아니요. 배열 또는 해시의 "상위 수준"만이 shared됩니다. 각 중첩된 요소도 shared로 만들어야 하며, 그렇지 않으면 내부 구조가 다른 스레드에서 보이지 않습니다.
스레드가 다른 스레드를 호출하여 exit로 종료할 수 있습니까?
아니요. exit는 프로세스를 완전히 종료시키며 개별 스레드를 종료시키지 않습니다. 스레드를 중지하는 것은 스레드 내부에서 exit를 사용하거나 join/detach 논리를 통해 관리해야 합니다.
두 스레드가 lock 없이 $counter :shared를 동시에 증가시킵니다. 최종 결과는 예상보다 적습니다(전형적인 lost update 문제).
장점:
단점:
공유 변수를 변경할 때마다 lock을 구현합니다. 큰 구조의 경우 요소별로 중첩 lock을 사용합니다.
장점:
단점: