C 多线程 malloc 全局访问错误

发布于 2024-10-19 03:46:44 字数 2349 浏览 7 评论 0原文

我有两个结构如下:

typedef struct _product
{
    unsigned int     product_id;
    time_t           my_time_stamp;
    unsigned int     lifespan;
} product;

typedef struct _queue
{
    product *   elem;
    struct _queue * next;
} queue;

我有一个全局变量头。

queue *head; 

在 main 中,我 malloc 队列的头部。

head = (queue *)malloc(sizeof(queue));

并在另一个函数中调用它

    if(head->elem == NULL) { head = newPointer; }

当我 malloc 头时一切都很好。然后,当它跳转到该函数时,它会重置为 0x0。

这是错误的方法吗?如果是的话应该怎么做呢?

void producer_func(void *tid)
{   
  while(number_of_products_created < number_of_products_max) //check for completeness of task
  {
    my_str("in producer with id ");
    my_int((long)tid);
    br();
    pthread_mutex_lock(&the_mutex);
    my_str("locked by ");
    my_int((long)tid);
    br();
    while(space_in_queue >= size_of_queue)
      pthread_cond_wait(&notFull, &the_mutex); //check to see if there is room in the queue

    product *tempProduct = malloc(sizeof(product));

    //////////////enter critical region/////////////
    tempProduct->product_id = product_id_count++;
    //////////////exit critical region/////////////

    //time
    struct timeval tim;
    gettimeofday(&tim, NULL);
    tempProduct->my_time_stamp = tim.tv_sec; 
    //endtime
    tempProduct->lifespan = rand();
    //new item for queue
    queue *newPointer = malloc(sizeof(queue));
    newPointer->elem = tempProduct;
    newPointer->next = NULL;                

    //critical region//
    if(head == NULL)
    {
      head = newPointer;
    }
    else
    {
      //traverse list
      queue *tempPointer;
      tempPointer = head;
      while(tempPointer->next != NULL)
      {
        tempPointer = tempPointer->next;
      }
      tempPointer->next = newPointer;
    }
    space_in_queue++;
    number_of_products_created++;
    //end critical region//

    my_str("unlocked by ");
    my_int((long)tid);
    br();
    usleep(10000);
    my_str("num products created is ");
    my_int(number_of_products_created);
    br();
    usleep(10000);
    pthread_cond_broadcast(&notEmpty);
    pthread_mutex_unlock(&the_mutex);
    usleep(100000); //let others have a chance
  }
}

I have 2 structs as follows:

typedef struct _product
{
    unsigned int     product_id;
    time_t           my_time_stamp;
    unsigned int     lifespan;
} product;

typedef struct _queue
{
    product *   elem;
    struct _queue * next;
} queue;

I have a global variable head.

queue *head; 

In main I malloc the head of the queue.

head = (queue *)malloc(sizeof(queue));

And Call it in another function

    if(head->elem == NULL) { head = newPointer; }

When I malloc the head everything is fine. Then when it jumps to the function it resets to 0x0.

Is this the wrong way to do this? If so how should it be done?

void producer_func(void *tid)
{   
  while(number_of_products_created < number_of_products_max) //check for completeness of task
  {
    my_str("in producer with id ");
    my_int((long)tid);
    br();
    pthread_mutex_lock(&the_mutex);
    my_str("locked by ");
    my_int((long)tid);
    br();
    while(space_in_queue >= size_of_queue)
      pthread_cond_wait(¬Full, &the_mutex); //check to see if there is room in the queue

    product *tempProduct = malloc(sizeof(product));

    //////////////enter critical region/////////////
    tempProduct->product_id = product_id_count++;
    //////////////exit critical region/////////////

    //time
    struct timeval tim;
    gettimeofday(&tim, NULL);
    tempProduct->my_time_stamp = tim.tv_sec; 
    //endtime
    tempProduct->lifespan = rand();
    //new item for queue
    queue *newPointer = malloc(sizeof(queue));
    newPointer->elem = tempProduct;
    newPointer->next = NULL;                

    //critical region//
    if(head == NULL)
    {
      head = newPointer;
    }
    else
    {
      //traverse list
      queue *tempPointer;
      tempPointer = head;
      while(tempPointer->next != NULL)
      {
        tempPointer = tempPointer->next;
      }
      tempPointer->next = newPointer;
    }
    space_in_queue++;
    number_of_products_created++;
    //end critical region//

    my_str("unlocked by ");
    my_int((long)tid);
    br();
    usleep(10000);
    my_str("num products created is ");
    my_int(number_of_products_created);
    br();
    usleep(10000);
    pthread_cond_broadcast(¬Empty);
    pthread_mutex_unlock(&the_mutex);
    usleep(100000); //let others have a chance
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

带刺的爱情 2024-10-26 03:46:44

锁定互斥体和释放互斥体之间的代码量非常大。您应该致力于最大限度地减少持有锁时完成的工作量。您应该完成所有工作,除了将项目添加到不带锁的列表中。只有当一切准备就绪后,您才能获取互斥体并继续添加项目并释放互斥体。将项目添加到列表末尾的操作可能是 O(1) 而不是 O(N) 的好主意 - 保留指向结构尾部的指针。如果在互斥体保持锁定的情况下一次休眠 10 毫秒,那么系统确实无法获得良好的性能(并发性)。

另一个批评是,您的产品结构在许多 64 位平台上将占用 24 个字节,而不仅仅是 16 个。如果 time_t 是一个 8 字节数量,并且 8 字节数量在 8 字节边界上对齐,在每个 unsigned int 值后面浪费了 4 个字节。

然而,这只是一般性的批评——并不是问题的直接根源。


实质性

您似乎没有初始化使用 malloc() 分配的queue。由于 malloc() 返回未初始化的数据,因此它可以包含任何内容。在执行其他操作之前,必须将其转换为格式正确的队列项 - 具有初始化的指针等。

That's an awful lot of code between locking the mutex and releasing it. You should aim to minimize the amount of work done with the lock held. You should do all the work except add the item to the list without the lock. Only when everything is ready do you grab the mutex and go ahead with adding the item and release the mutex. It might be a good idea to make adding the item at the end of the list an O(1) rather than O(N) operation too - keep a pointer to the tail of the structure. You really won't get good performance (concurrency) out of the system if you sleep for 10 milliseconds at a time with the mutex held locked.

Another critique is that your product structure will occupy 24 bytes on many 64-bit platforms, rather than just 16. If time_t is an 8-byte quantity and 8-byte quantities are aligned on 8-byte boundaries, you waste 4 bytes after each of the unsigned int values.

However, that's just general critique - not directly a source of your problem.


Substantive

You do not seem to be initializing the queue which you allocate with malloc(). Since malloc() returns uninitialized data, it can contain anything. Before you do anything else, you must turn it into a properly formed queue item - with initialized pointers etc.

悲歌长辞 2024-10-26 03:46:44

我认为 head 是一个全局变量。不知道为什么你的函数在那里找不到一个好的值,但是你可以通过不使用指针变量来避免所有问题:

queue head = {0};

然后你的列表将始终被很好地定义,你甚至不需要检查它。不过,您的列表是否为空的语义将会改变。

乔纳森是对的,您的关键部分中有大量代码。尤其是在这样的区域睡觉实在是一个坏主意。

I suppose that head is a global variable. No idea why your function doesn't find a good value in there, but you could avoid all your problems by just not having it a pointer variable:

queue head = {0};

Then your list would always be well defined and you'd never even have to check it. Your semantics for your list being empty or not would change though.

And Jonathan is right that you have an awful lot of code in your critical section. In particular, Sleeping inside such a section is really a bad idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文