>

pthread를 사용하여 행렬 곱셈을 수행하기위한 할당을위한 프로그램을 작성 중입니다. 행렬 크기n(매트릭스는 정사각형으로 가정)과p스레드 수n균등하게.AxB의 경우A는 수평으로p세그먼트로 분할되며 각 스레드는 입력으로 단일 세그먼트를 수신하고 전체 행렬B이며 결과 행렬C의 일부를 반환합니다.

내가 가진 문제는 실제로 과제 자체와 관련이 없지만 대답을 찾을 수 없었던 pthread의 성격에 대한보다 일반적인 문제입니다. 가능한 한 많이 제거하려고 노력할 것입니다. 내 행렬은 구조체 안에 1D 배열로 저장됩니다.

typedef struct matrix {
    int *matrix;
    int size;
} matrix_t

그들은 그렇게 할당되어 있습니다

matrix_t mtx = {
    malloc(input_size * input_size * sizeof(int)),
    input_size
};

함수에 의해 무작위로 채워집니다. 파티션은 2D 배열에 저장되며 주소는 함수에서 반환되지만 일반적인 방식으로 할당됩니다.

int **partitions = partitionmtx(mtx, num_threads);
int **partitionmtx(matrix_t mtx, int threads) 
{
    int partlen = mtx.size * (mtx.size / threads);
    int **parts = malloc(threads * sizeof(int));
    for(int i = 0; i < threads; ++i) {
        parts[i] = malloc(partlen * sizeof(int));
        // partitions populated...
    }
    return parts;
}

이것은 잘 작동합니다. 각 파티션을 스레드로 보낼 때 문제가 발생합니다. 스레드에 대한 인수를 단순하게 유지하기 위해 다음과 같이 묶었습니다.

typedef struct operand {
    matrix_t matrix;
    int *partition;
    int partition_length;
} operand_t;

나는 다음과 같이 pthread를 만들고있다 :

pthread_t threads[num_threads];
pthread_mutex_init(&mymutex, NULL);
int rc;
for(int i = 0; i < num_threads; ++i) {
    operand_t op = {matrix, partitions[i], partition_length};
    rc = pthread_create(&threads[i], NULL, partition_product, (void *)&op);
    assert(rc == 0);
}
for(int i = 0; i < num_threads; ++i) {
    rc = pthread_join(threads[i], NULL);
    assert(rc == 0);
}

partition_product 함수로 이동합니다. 내 우선 순위는 분명히 모든 스레드가 올바른 데이터를 가져 오는지 확인하는 것이므로 각 스레드의 내용을 인쇄했습니다.

void* partition_product(void *args)
{
    operand_t *op = (operand_t *)args;
    pthread_mutex_lock(&mymutex);
    printf("Matrix:\n);
    printmtx(op->matrix); // This is a function I defined but its details aren't relevant here
    printf("\nPartition:" );
    for(int i = 0; i < op->partition_length; ++i)
        printf("%4d", op->partition[i]);
    pthread_mutex_unlock(&mymutex);
}

여기에 문제가 생겼습니다. 매트릭스는 문제없이 스레드에서 인쇄합니다. 문제는 모든 스레드가 하나 이상의 스레드를 지정하면 예를 들어

./threadmatrix -n 4 -p 4

모두 같은 파티션을 인쇄했습니다. 나는 이것이 스레드에서 인쇄의 부작용 일 수 있다고 생각했기 때문에 인쇄물의 뮤텍스 잠금. 그런 다음 원래 스레드와 생성 된 스레드에서 각 파티션의 주소를 인쇄하여 어떤 일이 발생했는지 확인하고 각 스레드가 생성 시점에서 동일한 주소를받는 것 같습니다. 스레드에 데이터를 가져 와서 문제없이 조작 할 수있는 것처럼 보이지만 모두 동일한 데이터입니다. 특히, 그들은 항상 마지막 파티션의 주소를 얻습니다. 내가 아는 모든 좋은 포인터 연습을 시도했지만 여전히 파티션 [i]의 주소가 0x00007ffffde234 인 경우, 위의 호출 인쇄 주소 0x00007ffffde234의 4 개 스레드가 모두 있습니다. 나는 약간의 설명을 위해 높고 낮은 것을 검색했지만 아무것도 찾지 못했습니다. 내가 뭘 잘못하고 있니?

  • 답변 # 1

    문제가 있습니다 :

    operand_t op = {matrix, partitions[i], partition_length};
    rc = pthread_create(&threads[i], NULL, partition_product, (void *)&op);
    
    

    마지막 인수에서 전달하는 포인터는 op 에 대한 포인터입니다. 스택에 있습니다. 문제는 메인 스레드가 for 루프의 반복을 완료하자마자 op 입니다.  루프의 다음 반복을 위해 파괴되고 다시 생성됩니다. 이것은 나중에 자식 스레드가 실행을 시작하고 포인터 인수를 사용하려고 할 때 operand_t 를 의미합니다.  포인터가 가리키는 것은 더 이상 유효하지 않습니다. (귀하의 경우, 생성 된 모든 하위 스레드에 대해 동일한 스택 메모리 위치가 재사용되고 있으며 이는 현재보고있는 동작을 부분적으로 설명합니다)

    이 문제를 피하려면 포인터를 전달하는 객체의 수명이 자식 스레드가 객체의 필드를 읽기 위해 포인터를 역 참조 할 때 객체가 계속 유효 할 정도로 길어야합니다. 가장 쉬운 방법은 힙에 객체를 할당하는 것입니다.

    operand_t * op = (operand_t *) malloc(sizeof(operand_t));
    op->matrix = matrix;
    op->partition = partitions[i];
    op->partition_length = partition_length;
    rc = pthread_create(&threads[i], NULL, partition_product, (void *)op);
    
    

    유일한 (작은) 캐치는 이제 당신의 자식 스레드가 free 를 호출 할 책임이 있다는 것   operand_t * 에  해당 객체를 사용한 후에 수신됩니다. 그렇지 않으면 메모리가 누출됩니다.

  • 이전 javascript - 두 문자열 (또는 배열)을 비교하고 순서에 관계없이 유사성의 %를 반환해야합니다
  • 다음 spring mvc - 이름이 'SpringMVC'인 DispatcherServlet에서 URI [/ SpringMVC /]가있는 HTTP 요청에 대한 맵핑이 없습니다