我已经实现了堆内存管理,现在我不确定两点(在代码之后解释):
所以堆内存管理基本上是这样实现的:
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
对其进行了测试,并且没有显示无效的读取或写入。
感谢您的帮助......
答案 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。