2010-03-24 2 views
5

나는 나무 구조의 데이터를 포함하는 속도가 중요한 다중 스레드 프로그램을 가지고있다.트리 구조와 스레드

typedef struct 
{ 
    // data pertaining to linkages, defining the architecture of the tree 
    int parent_node; 
    int child_node[MAX_CHILD_NODES]; 
    int number_of_children; 

    // data pertaining to info at each node 
    float interesting_info_A; 
    char interesting_info_B[STRING_LEN]; 
    long interesting_info_C; 
} 
node_type; 

node_type node[MAX_NUMBER_OF_NODES]; 

CRITICAL_SECTION node_critsec[MAX_NUMBER_OF_NODES]; 

node_critsec []가 제어하는 ​​중요 섹션에 들어가고 나가는 프로그램입니다. 그래서 노드 n의 interesting_info_A/B/C를 처리 할 필요가있을 때 그 노드 (node_critsec [n])의 임계 구역에 들어가서 처리를 수행 한 다음에 나가십시오. 이 프로그램은 나무 주위를 순회하면서 부모와 자녀와의 연결을 따라 복잡한 경로를 취합니다. 프로그램은 또한 트리를 성장 시키며, 즉 새로운 노드를 추가하고 그에 따라 다른 노드의 부모/자식 링크를 수정한다 (트리는 결코 줄어들지 않는다). 나는 각 스레드가 교착 상태의 위험을 피하기 위해 한 번에 하나의 노드 만 잠그도록하려고합니다. 그런데 문제가 생깁니다. 새 노드를 추가하는 경우 노드의 부모를 잠궈서 자식 목록을 조정할 수 있습니다. 교착 상태 또는 동일한 노드에서 데이터 수정을 시도하는 두 개의 스레드없이 모두 작업하려면이 작업을 악몽이되고 있습니다. 거기에 따라야 할 지침 원칙이 있습니까? 내가 따라야 할 노드를 잠 그거나 잠금을 해제 할 노드가 있습니까? 아니면 그냥 초능력이 있어야하고 발생할 수있는 모든 순열을 해결해야합니까?

+0

교착 상태가 발생하는 위치를 설명 할 수 있습니까? 즉, 그래프 (나무가 아님)에 루프가 있거나 순회 중에 자물쇠를 가져 오기 전에 부모 자물쇠를 포기하지 않으면 수정하기가 매우 쉽다는 것을 의미합니다. –

+0

내가 이해하는 한, 일부 알고리즘은 상향식으로 진행되는 반면 다른 알고리즘은 하향식으로 진행되는 식으로 진행됩니다. 나는 그가 다른 노드가 새로운 노드를 훔치거나 awry (일관성없는 상태 : parent_node가 이것을 나열하지 않는 노드로 설정 될 수 있기 때문에 부모 노드의 목록에 추가하기 전에 새로운 노드에 잠금을 유지해야한다는 의미라고 생각한다. 자식 노드). 이 데이터 구조가 최적인지는 모르겠지만이 구조와의 동기화 필요성에 대해서는 옳은 것으로 간주합니다. – gimpf

+0

@Tyler McHenry : 저는 과거에도 불구하고 실제로 교착 상태에 빠져있는 것은 아닙니다. 내가 가지고있는 시간은 언제나 동시에 두 개의 다른 노드를 잠그고있는 스레드 중 하나로 떨어졌습니다. 내 문제는 이제 두 개의 다른 스레드가 동일한 노드 데이터를 처리하는 유형입니다. – Mick

답변

14

간단한 규칙 : 여러 항목을 잠글 때 교착 상태를 피하려면 모든 항목을 항상 같은 순서로 잠급니다. 따라서 항목 A, B, C, D가있는 경우 알파벳 순서로 잠그고 다른 항목은 잠글 수 없습니다. C를 잠그고 B가 필요하다고 결정하면 C를 놓은 다음 B를 잠 가야하고 C를 다시 잠 가야합니다.

트리에서는 항상 위에서 아래로 잠글 수 있습니다. 부모를 잠 그려면 필요에 따라 잠금을 해제하고 다시 획득하십시오.

다른 스키마도 마찬가지로 작동하지만이 방법은 간단합니다.

편집 : 그것에 대해 조금 읽을 수 있습니다 here.

+0

올바른 것으로 가정하면 나는 그 소리를 좋아한다. 좋고 간단합니다. – Mick

+1

@Mick : 네 - 그 계획은 교착 상태를 피하기 위해 정확합니다. –

+1

나는 이것이 올바른 계획이라고 생각할 것입니다. 특히 위에서 아래로 트리를 잠그는 것이 좋습니다. 노드의 부모를 잠 그려면 현재 노드 잠금을 해제하고 부모 노드로 이동하여 순서대로 쌍을 잠급니다. –

1

트리를 자라는 것이 상대적으로 드문 경우, 하나의 가능성은 여러 개의 판독기를 허용하지만 하나의 작성기 만 허용하는 읽기/쓰기 잠금을 사용하는 것입니다. 순회 중 하나의 R/W 잠금을 사용하여 트리 자체를 잠급니다 (읽기 잠금 획득). 임의의 수의 스레드가이를 수행 할 수 있습니다. 스레드가 새 노드를 추가해야 할 때 쓰기 잠금을 획득합니다. 이렇게하면 업데이트가 진행되는 동안 모든 독자가 차단됩니다. 굶주림을 피하기 위해 작가에게 우선권을주기 위해 읽기/쓰기 잠금을 설정해야 할 것입니다.

이 메커니즘을 사용하면 단일 스레드가 개별 노드에 대해 여러 개의 중요한 섹션을 가져 와서 프로세스를 단순화 할 필요가 없습니다.

+0

불행히도 나무를 키우는 것은 매우 일반적입니다. – Mick

+0

@Mick : 새로운 노드는 어떻게 부모 노드에 추가됩니까? 특정 순서 (예 : b-tree 스타일)로 추가 되었습니까? 또는 자식 노드가 기존 노드의 끝에 간단하게 추가됩니까 (number_of_children 위치)? –

+0

불행히도 메커니즘은 내 질문에 간결한 코드보다 복잡합니다 ... 그리고 귀하의 질문에 적절하게 답변하기 위해서는 너무 많은 것을 설명해야합니다. 그러나 clintp의 대답은 내 모든 문제를 해결할 수 있습니다. – Mick

1

이것은 파일 시스템의 노드 잠금을 상기시킵니다. 참고 자료를 찾고 있다면 리눅스, BSD, 오픈 솔라리스의 VFS 레이어를 체크 아웃 할 수 있습니다. 그러나 복잡한 작업이 될 수 있으므로 참고할만한 최상의 예제가 아닐 수 있습니다.

나는 clintp가 만든 점 이외에 몇 가지 사항을 추가하고 싶습니다 (그의 요점에 유의하십시오).

  1. 당신이 그것을 필요로하고 당신이 완료되면 다음 잠금을 해제 전체 트리에 대한 액세스를 잠글 뮤텍스를 사용하는 것이 가치가있을 수 있습니다. 이 중요한 섹션에서이 단일 스레드로 응용 프로그램을 처리 할 수 ​​있지만 작업을 빠르고 안전하게 진행하는 것이 유용 할 수 있습니다. 누구가 알고 있, 이것이 제안하는 성과는 충분히 좋을지도 모릅니다. 그렇지 않다면 적어도 앞으로 나아갈 수 있습니다. 뮤텍스 대신 읽기 - 쓰기 세마포어를 사용하면 병목 현상이 완화 될 수 있습니다. 모든 것은 쓰기를위한 단일 스레드가되고, 동시에 읽기가 가능합니다.

  2. 트리에 대한 모든 작업 목록을 만들고 항목을 분류 (읽기, 쓰기, 업데이트, 이동, 이름 바꾸기, 삭제 등)하고 원하는 동시성을 파악합니다. 당신이 쓴 것에서부터 읽기 전용 이상의 것을 필요로합니다. 스레드 A가 스레드 B가 쓰기 위해 잠겨 있지 않은 노드를 읽을 수 있도록 하시겠습니까? 나는 경험을 통해이 단계를 건너 뛰면 많은 시간을 들일 수 있다고 말한다.

희망이 있습니다.

관련 문제