mallo c () возвращает один и тот же адрес несколько раз, даже если я не использовал free () - PullRequest
0 голосов
/ 30 марта 2020

РЕДАКТИРОВАТЬ: я использовал free (), игнорировать заголовок.

Суть в том, что каждый раз, когда вызывается malloc(), возвращается адрес 0x8403620 , который я выяснил с помощью Gdb.

tellers[i] = create_teller(0, i, NULL);

Сначала я использую malloc() в строке 72, чтобы создать 3 структуры кассира. Первый возвращенный адрес, видимый через Gdb, является 0x84003620 . Второй 0x84033a0 , третий 0x84034e0 . Все выглядит нормально.

clients[i] = create_client(0, i, -1, -1);

Затем я использую malloc() в строке 77 с функцией create_client() для создания 100 клиентов. Первый адрес, присвоенный клиенту [0], это ... 0x8403620 . Так же, как кассиры [0]. Становится хуже. Следующий адрес, возвращаемый из malloc(), снова равен 0x8403620 , когда i = 1, и т. Д. Для i = 3, 4, ..., 99.

Это не присуще функции create_client() или create_teller(), но вместо этого сама функция malloc().

Это просто очень странная ситуация.

Теперь я хотел бы спросить : я неправильно использую malloc()? Или моя версия malloc() прослушивается и мне следует каким-то образом переустанавливать ее? Скорее всего, это мой код, поскольку он работает для создания кассиров, но не для клиентов.

Вот полный код:

#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <assert.h>


typedef struct teller teller_t;
typedef struct client client_t;

teller_t *  create_teller (pthread_t thread_id, int id, client_t *assigned_client);
client_t *  create_client (pthread_t thread_id, int id, int operation, int amount);
void *      run_teller (void *arg);
void *      run_client (void *arg);

/* types of operations */
#define DEPOSIT     0
#define WITHDRAW    1

#define NUM_TELLERS 3
#define NUM_CLIENTS 100

struct client {
    pthread_t thread_id;

    int id;
    int operation;
    int amount;
};

struct teller {
    pthread_t thread_id;

    int id;
    bool available;
    client_t *assigned_client;
};

client_t *clients[100];
teller_t *tellers[3];

/* only 2 tellers at a time can access */
sem_t safe;
/* only 1 teller at a time can access */
sem_t manager;
/* amount of tellers available, at most 3 */
sem_t line; /* rename to available? */
/* each teller waiting for a client to be assigned to them */
sem_t wait_for_client[3];


int
main (int argc, char **argv) {
    (void) argc; 
    (void) argv;

    srand(time(NULL));

    /* This also tells us how many clients have been served */
    int client_index = 0;

    sem_init(&safe, 0, 2);
    sem_init(&manager, 0, 1);
    sem_init(&line, 0, 0);
    for (int i = 0; i < 3; i++) 
        sem_init(&wait_for_client[i], 0, 0);

    for (int i = 0; i < NUM_TELLERS; i++) {
        tellers[i] = create_teller(0, i, NULL);
        pthread_create(&tellers[i]->thread_id, NULL, run_teller, (void *) tellers[i]);
    }

    for (int i = 0; i < NUM_CLIENTS; i++) {
        clients[i] = create_client(0, i, -1, -1);
        pthread_create(&clients[i]->thread_id, NULL, run_client, (void *) clients[i]);
    }

    /* DEBUG
    for (int i = 0; i < NUM_CLIENTS; i++) {
        printf("client %d has id %d\n", i, clients[i]->id);
    }
    */

    // No threads should get past this point!!!
    // ==------------------------------------==

    // Should all of this below be handled by the clients instead of main?

    while (1) {
        if (client_index >= NUM_CLIENTS) {
            // TODO:
            // tell tellers that there are no more clients 
            // so they should close, then then close the bank.

            break;
        }

        sem_wait(&line);

        for (int i = 0; i < 3; i++) {
            if (tellers[i]->available) {
                int client_id = clients[client_index]->id;

                //printf("client_index = %d\n", client_index); // DEBUG

                tellers[i]->assigned_client = clients[client_index++];
                tellers[i]->available = false;


                printf(
                    "Client %d goes to Teller %d\n", 
                    client_id, 
                    tellers[i]->id
                );

                sem_post(&wait_for_client[i]);

                break;
            }
        }

        //sem_post(&line); // Is this needed?
    }

    return EXIT_SUCCESS;
}


teller_t *  
create_teller (pthread_t thread_id, int id, client_t *assigned_client) {
    teller_t *t = (teller_t *) malloc(sizeof(teller_t));
    if (t == NULL) {
        printf("ERROR: Unable to allocate teller_t.\n");
        exit(EXIT_FAILURE);
    }

    t->thread_id = thread_id;
    t->id = id;
    t->available = true;
    t->assigned_client = assigned_client;

    return t;
}

/* TODO: Malloc returns the same address everytime, fix this */
client_t *  
create_client (pthread_t thread_id, int id, int operation, int amount) {
    client_t *c = malloc(sizeof(client_t));

    if (c == NULL) {
        printf("ERROR: Unable to allocate client_t.\n");
        exit(EXIT_FAILURE);
    }

    c->thread_id = thread_id;
    c->id = id;
    c->operation = operation;
    c->amount = amount;

    return c;
}


void *
run_teller (void *arg) {
    teller_t *t = (teller_t *) arg;

    printf("Teller %d is available\n", t->id);

    while (1) {
        /* tell the line that a teller is available */
        sem_post(&line); 
        /* pass when the line assignes a client to this teller */
        sem_wait(&wait_for_client[t->id]); 

        assert(t->assigned_client != NULL);

        if (t->assigned_client->operation == WITHDRAW) {

        }
        else {

        }
    }

    free(arg);

    pthread_cancel(t->thread_id);
    return NULL;
}


void *
run_client (void *arg) {
    client_t *c = (client_t *) arg;

    c->operation = rand() & 1;

    printf(
        "Client %d waits in line to make a %s\n", 
        c->id, 
        ((c->operation == DEPOSIT) ? "Deposit" : "Withdraw")
    );

    free(arg);

    pthread_cancel(c->thread_id);
    return NULL;
}

1 Ответ

0 голосов
/ 30 марта 2020

Затем я использую mallo c () в строке 77 с функцией create_client () для создания 100 клиентов.

Не совсем, вы создаете один объект, затем создаете поток, который управляет этим объектом, run_client(), а затем повторяете. Но run_client() в основном ничего не делает, кроме free() вашего клиентского объекта! Так что malloc совершенно верно возвращает тот же адрес снова, так как теперь это свободная память.

Просто так получается, что потоки вашего клиента быстрее, чем ваш основной. Ваша проблема здесь в том, что вы освобождаете объекты от вторичных потоков, оставляя висячие указатели в массиве глобальных указателей. Если вы используете этот массив для целей отладки, то здесь на самом деле все в порядке, но если вы хотите использовать объекты клиента когда-нибудь в будущем, то вам не следует free ваших клиентов.

...