malloc() 多次返回相同的地址,即使我没有使用 free()

malloc() is returning the same address multiple times, even when I haven't used free()

编辑:我确实使用了 free(),请忽略标题。

大意是每次调用malloc(),地址0x8403620 返回,这是我使用 Gdb 发现的。

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

我首先在第 72 行使用 malloc() 创建了 3 个出纳器结构。通过 Gdb 可见的第一个返回地址是 0x84003620。第二个是 0x84033a0,第三个0x84034e0。一切似乎都很好。

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

然后我在第 77 行使用 malloc()create_client() 函数来 创建 100 个客户端。分配给 client[0] 的第一个地址是 ... 0x8403620。与出纳员[0] 相同。情况变得更糟。下一个地址 当 i = 1 时,从 malloc() 返回的是 0x8403620,等等 为 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;
}

Then I use malloc() on line 77 with the create_client() function to create 100 clients.

不完全是,您创建一个对象,然后生成一个线程来管理该对象,run_client() 然后重复。但是 run_client() 除了 free() 你的客户对象,基本上什么都不做!所以 malloc 再次返回相同的地址是完全正确的,因为它现在是空闲内存。

碰巧您的客户端线程比您的主线程快。您的问题是您正在从辅助线程中释放对象,同时将悬空指针留在全局指针数组中。如果您将该数组用于调试目的,那么这里实际上并没有错,但是如果您想在将来的某个时候使用客户端对象,那么您不应该首先 free 您的客户端。