指针解除引用线程是否安全?

时间:2014-03-09 15:45:01

标签: c multithreading pointers mutex

我已经实现了堆内存管理,现在我不确定两点(在代码之后解释):

所以堆内存管理基本上是这样实现的:

struct memory {
     // Mutex for thread safe operations
     pthread_mutex_t _mutex;
     // Memory size
     size_t _size;
};

int allocMemory(void **memoryPointer, const size memorySize)
{
     void *memory;
     struct memory *internal;

     /* Checking arguments... */
     memory = malloc(memorySize + sizeof(struct memory));

     if (memory == NULL) return ENOMEM;

     internal = (struct memory *)memory;

     pthread_mutex_init(&internal->_mutex);
     internal->_size = memorySize;

     // Set pointer with offset
     *memoryPointer = memory + sizeof(struct memory);

     return 0;
}

int reallocMemory(void **memoryPointer, const size newMemorySize)
{
     /* Checking arguments... */
     {
         void *memory;
         void *memoryWithoutOffset;
         struct memory *internal;

         // Get pointer         v--- is this thread safe?
         memory               = *memoryPointer;
         // Subtract offset
         memoryWithoutOffset  = memory - sizeof(struct memory);
         // Get internal data (for _mutex)
         internal             = (struct memory *)memoryWithoutOffset;

         pthread_mutex_lock(&internal->_mutex);
         {
             void *newMemory;
             newMemory = realloc(memoryWithoutOffset, sizeof(struct memory) + internal->_size + newMemorySize);
             if (newMemory != NULL) {
                  // Refresh pointer to "internal" because its location may have been changed
                  internal = (struct memory *)newMemory;
                  internal->_size += newMemorySize;

                  // Add offset
                  *memoryPointer = newMemory + sizeof(struct memory);
             }
         }
         pthread_mutex_unlock(&internal->_mutex);
     }

     return 0;
}

在我的主文件中,我有类似的内容:

void *myMemory;

void *threadFunction(void *arg)
{
     //             v--- reference to `myMemory`
     reallocMemory(&myMemory, 100);

     return NULL;
}

int main(int argc, const char **argv)
{
     pthread_t thread;

     allocMemory(&myMemory, 10);

     /* ... */
     for (int i = 0; i < 5; ++i) {
          pthread_create(&thread, NULL, threadFunction, NULL);
     }
     /* ... joining threads etc. */
     return EXIT_SUCCESS;
}

我的问题是,在我锁定互斥锁之前,我必须从给定的指针引用中“提取”它。这个指针解除引用会破坏线程安全吗? memory = *memoryPointer

这是“隐藏”指针中的结构是一种安全/良好的做法吗?

顺便说一句:我已经用valgrind对其进行了测试,并且没有显示无效的读取或写入。

感谢您的帮助......

2 个答案:

答案 0 :(得分:3)

不,它不是线程安全的。考虑两个带有myMemory指针的线程,如果一个线程重新分配myMemory,另一个线程如何知道它的myMemory指针现在无效(realloc可能会移动内存块)。

您可能需要考虑使用固定位置结构,如:

struct memory {
     pthread_mutex_t _mutex;    // Mutex for thread safe operations
     size_t _size;              // Memory size
     void *memory_ptr;          // pointer to memory
};

然后使用(伪代码)函数分配,重新分配和访问您的内存:

alloc_memory()
   malloc struct memory
   memory_ptr= malloc memory reqd
   fill in memory struct

reallocMemory( struct memory *, new_size )
   obtain mutex
   reallocate memory pointed to by memory_ptr
   release mutex

void * start_access_memory( struct memory *)
   obtain mutex
   return memory_ptr

end_access_memory( struct memory *)
   release mutex

这样每个线程都可以有一个指向内存结构及其互斥锁的持久指针。

答案 1 :(得分:1)

不,它不是线程安全的。

两个线程可以同时访问内存位置myMemory,并且至少有一个操作是写访问。这称为数据竞争,而C11表示,具有数据竞争的程序具有未定义的行为 - 与C ++ 11完全相同。

两个相关的行是:

  memory               = *memoryPointer;
  *memoryPointer = newMemory + sizeof(struct memory);

您必须为变量myMemory使用 atomic 变量。不幸的是,AFAIK GCC-4.7不支持C11。