Помощь с основной концепцией нарезки резьбы / условиями гонки - PullRequest
2 голосов
/ 06 января 2009

Я изучаю потоки POSIX прямо сейчас, но я думаю, что это всего лишь общий вопрос о многопоточности, поэтому я надеюсь, что кто-нибудь может мне помочь. У меня есть пример из книги, над которой я работаю, которая демонстрирует состояние гонки:

void *thread_main(void *thread_number) {
    printf("In thread number %d.\n", *(int *)thread_number);
}

void main() {
    int i = 0;
    pthread_t thread;

    for( i = 0; i < 10; i++ ) {
        printf("Creating thread %d.\n");
        pthread_create(&thread, 0, thread_main, &i);
        printf("Created thread %d.\n");
    }
}

Есть несколько вещей, которые я не понимаю по этому поводу. Сначала «В теме № 5». печатается много раз, даже если это не должно быть в потоке номер 5. В книге, пример показывает, что поток 8 печатается много раз. Я также не понимаю ту часть, которая говорит *(int *)thread_number. Я попытался изменить это на номер_потока, но это снова и снова давало мне странные числа.

Книга на самом деле не объясняет этого. Может кто-нибудь дать мне четкое объяснение того, что здесь происходит? Я не понимаю, почему он не печатает что-то вроде:

> Creating thread 1.
> In thread number 1.
> Created thread 1.
> Creating thread 2.
> In thread number 2.
> Created thread 2.

Я знаю это, потому что он многопоточный: «В потоке с номером x». часть будет приходить в разное время, но я действительно не понимаю, почему нет точно 10 «В номере нити x» с одной строкой для каждого потока, который я создал!

~ Дези

Ответы [ 3 ]

3 голосов
/ 06 января 2009

Возможно, что цикл for может выполнить итерацию 10 раз, прежде чем любой из 10 созданных потоков сможет запустить. В этом случае значение *thread_number будет равно 10 для каждого потока (поскольку это указатель на одну ячейку памяти с одним значением).

Если вы не передадите указатель на i на pthread_create, тогда значение int будет рассматриваться как адрес, поэтому, когда вы разыменовываете его в thread_main, вы получаете доступ некоторая произвольная ячейка памяти, содержимое которой, вероятно, не определено. Тебе повезло, что в этом случае ты не сегфолтинг.

Если вы хотите увидеть правильное значение для *thread_number в каждом потоке, вам нужно malloc новый int перед вызовом pthread_create и присвоить ему текущее значение i, например, так:

for( i = 0; i < 10; i++ ) {
    int *thread_count = malloc(sizeof(int));
    *thread_count = i;
    printf("Creating thread %d.\n", i);
    pthread_create(&thread, 0, thread_main, thread_count);
    printf("Created thread %d.\n", i);
}

Конечно, тогда вам понадобится free память, когда с ней закончится поток, вот так:

void *thread_main(void *thread_number) {
    printf("In thread number %d.\n", *(int *)thread_number);
    free(thread_numbr);
}
3 голосов
/ 06 января 2009

Прежде всего, * (int *) thread_number - это указатель - когда у вас был только номер_потока, "странными числами" были адреса указателя на 'i' из функции main (и если только I ' Я ошибаюсь, что все они должны были быть одинаковыми для одного запуска программы (поэтому каждый из 10 потоков должен был иметь одинаковое значение «В номере потока [число]»)).

Вы должны понимать, что это были указатели на повторяющиеся 5, чтобы иметь смысл - каждый поток работал с одним и тем же базовым i из функции main - он не копировался для каждого нового потока, поэтому при увеличении значения i в функции main это отражалось для номера_потока в функции thread_main .

Последняя часть головоломки состоит в том, что время установки для каждого нового потока, а затем переключение контекста (изменение того, какой поток фактически выполняется) не является немедленным, поэтому в вашем случае цикл for выполняется 5 раз перед вновь созданными потоками. фактически выполняются (и в случае с книгой цикл for запускается 8 раз перед переключением контекста), тогда каждый из потоков смотрит на одно и то же базовое значение i, которое теперь равно 5.

1 голос
/ 06 января 2009

Во-первых, состояние гонки - это плохо. Эта программа должна не работать так, как вы ожидаете. Состояние гонки означает, что программа предназначена для разрыва.

В этом случае похоже, что все ваши темы разделяют переменную i. Вы передаете им ссылки на одну общую переменную, о которой они пытаются сообщать всякий раз, когда они планируются.

...