Deallocating memory in multi-threaded environment.


 
Thread Tools Search this Thread
Top Forums Programming Deallocating memory in multi-threaded environment.
# 1  
Old 04-29-2011
Deallocating memory in multi-threaded environment.

I'm having a hard time figuring out how to manage deallocation of memory in multithreaded environments. Specifically what I'm having a hard time with is using a lock to protect a structure, but when it's time to free the structure, you have to unlock the lock to destroy the lock itself. Which will cause problems if a separate thread is waiting on that same lock that you need to destroy.

I'm trying to come up with a mechanism that has retain counts, and when the object's retain count is 0, it's all freed. I've been trying a number of different things but just can't get it right. As I've been doing this it seems like you can't put the locking mechanism inside of the structure that you need to be able to free and destroy, because that requires you unlock the the lock inside of it, which could allow another thread to proceed if it was blocked in a lock request for that same structure. Which would mean that something undefined is guaranteed to happen - the lock was destroyed, and deallocated so either you get memory access errors, or you lock on undefined behavior..

Would someone mind looking at my code? I was able to put together a sandboxed example that demonstrates what I'm trying without a bunch of files.

Code:
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

struct xatom {
	short rc;
	pthread_rwlock_t * rwlck;
};
typedef struct xatom xatom;

struct container {
	xatom * atom;
};
typedef struct container container;

#define nr 1
#define nw 2
pthread_t readers[nr];
pthread_t writers[nw];

container * c;

void  retain(container * cont);
void  release(container ** cont);
short retain_count(container * cont);

void * rth(void * arg) {
	short rc;
	while(1) {
		if(c == NULL) break;
		rc = retain_count(c);
	}
	printf("rth exit!\n");
	return NULL;
}

void * wth(void * arg) {
	while(1) {
		if(c == NULL) break;
		release((container **)&c);
	}
	printf("wth exit!\n");
	return NULL;
}

short retain_count(container * cont) {
	short rc = 1;
	pthread_rwlock_rdlock(cont->atom->rwlck);
	printf("got rdlock in retain_count\n");
	rc = cont->atom->rc;
	pthread_rwlock_unlock(cont->atom->rwlck);
	return rc;
}

void retain(container * cont) {
	pthread_rwlock_wrlock(cont->atom->rwlck);
	printf("got retain write lock\n");
	cont->atom->rc++;
	pthread_rwlock_unlock(cont->atom->rwlck);
}

void release(container ** cont) {
	if(!cont || !(*cont)) return;
	container * tmp = *cont;
	pthread_rwlock_t ** lock = (pthread_rwlock_t **)&(*cont)->atom->rwlck;
	pthread_rwlock_wrlock(*lock);
	printf("got release write lock\n");
	if(!tmp) {
		printf("return 2\n");
		pthread_rwlock_unlock(*lock);
		if(*lock) {
			printf("destroying lock 1\n");
			pthread_rwlock_destroy(*lock);
			*lock = NULL;
		}
		return;
	}
	tmp->atom->rc--;
	if(tmp->atom->rc == 0) {
		printf("deallocating!\n");
		*cont = NULL;
		pthread_rwlock_unlock(*lock);
		if(pthread_rwlock_trywrlock(*lock) == 0) {
			printf("destroying lock 2\n");
			pthread_rwlock_destroy(*lock);
			*lock = NULL;
		}
		free(tmp->atom->rwlck);
		free(tmp->atom);
		free(tmp);
	} else {
		pthread_rwlock_unlock(*lock);
	}
}

container * new_container() {
	container * cont = malloc(sizeof(container));
	cont->atom = malloc(sizeof(xatom));
	cont->atom->rwlck = malloc(sizeof(pthread_rwlock_t));
	pthread_rwlock_init(cont->atom->rwlck,NULL);
	cont->atom->rc = 1;
	return cont;
}

int main(int argc, char ** argv) {
	c = new_container();
	int i = 0;
	int l = 4;
	for(i=0;i<l;i++) retain(c);
	for(i=0;i<nr;i++) pthread_create(&readers[i],NULL,&rth,NULL);
	for(i=0;i<nw;i++) pthread_create(&writers[i],NULL,&wth,NULL);
	sleep(2);
	for(i=0;i<nr;i++) pthread_join(readers[i],NULL);
	for(i=0;i<nw;i++) pthread_join(writers[i],NULL);
	return 0;
}

Thanks for any help!
# 2  
Old 04-29-2011
C# and JAVA have garbage collection, and there are open source c# out there.

If you allocate using a flat file and mmap()/mmap64(), unused memory is virtual at best, and you have a hard copy you can interrogate during and after a process run. If there is temp file space used that is not mapped, who cares?

Architecturally, locks are less of a need if you send messages from each thread in its own simple queue (one writer per queue, one reader) to a manager for service. The manager can just poll the queues for services, and send any response back on a reverse queue.

I think, generally, you are right that you need a lock outside the thing deallocated, with a pointer to it, to ensure that you can deallocate it in peace. You have a struct with a count, a pointer originally null and a mutex. Everyone that takes a copy of the pointer locks, checks for null pointer, increments, takes the copy and unlocks. When done with the object, they lock, decrement and unlock. Someone has to malloc and load the pointer to make it usable. Someone has to deallocate it when nobody cares any more, but the counter only tells you how many copies are in use, not if there is no future interest. Even if no copies are outstanding, the users could want a copy, so destruction on 0 copies is an application-specific question. But the parent structure is not deallocated. It could be in a tree, so only the root is always there. That might not scale well. With most containers, usually there is a non-dynamic pointer at the top, like head=null for an empty linked list.

I have not found locks and mutexes to be important to life as it know it. Threads can be managed much like IPC, or using monotonically increasing controls so a thread may be behind, temporarily, but never ahead, like a modulo-two sized ring buffer controlled by a long long and a bit mask (size - 1) as an in-process queue. If each thread feeds off a dispatcher thread via an input queue, it just dequeues work and writes other queues, possibly to a work collector thread. Threads with nothing to do need something like a block on the queue, hard to achieve internally. Sleep of any length may delay processing. That is a classic poll-interrupt-block conundrum.
# 3  
Old 04-29-2011
Did you respond in the right thread? What you're explaining doesn't seem to be of any relevance to my question. But it's a good explanation of something Smilie.
# 4  
Old 04-29-2011
Yes, where did you fall off my wagon?

The big answer is no, this cannot work. You can only dealloc when you are sure all copies of the pointer, or any derived pointer, are out of use, forever. Threads need to use the pointer to see if it is locked.
# 5  
Old 04-29-2011
I lost track of what you were saying in the last paragraph. Are you suggesting that I have a separate thread that does deallocation? There could still be a problem with that - it could be added twice to the deallocation thread.

Have you ever been able to find examples of this type of situation. Most pthread references I look at don't go into any detail about complicated situations like this - they just show you what a mutex is and leave it at that.
# 6  
Old 04-29-2011
Threads is having two cooks in the kitchen, but as far as free(), same old problem. Once you free(), nobody should use the pointer or any derived pointer, and nice people set it to null for testing, and start it out that way, too. Threads adds a race condition, where only a mutex and similar IPC-ish mechanisms can tell another thread anything, so you needs to be sure they will never reference the space before your free. Your scheme has the controlling mutex in the deallocated space. It is a bit like an elevator with no outside door. You do not want to test for the car with your foot, as a passing car will cut your leg off.

The garbage collection languages free things when all references are gone. You put your finger on a big language limitation/feature. Early JAVA would be fooled by data that looked like a pointer to the object, and not always free the object!

You can manage the deallocation in a stable way in many applications, like a buffering input reader, which hangs read data on a linked list that it creates, and there is a consumer-owned-flag so when it has been consumed, the reader knows it can reuse it. The consumer might just null the pointer in an indirect linked list, and free() the space so it could return to the arena, but the arena might become fragmented (hint: bsdmalloc()!). If the buffers can be reused, it might be good for them all to be the same size, but if not, they can be just big enough. The critical part is that the references are stable, the reader creating, writing and destroying everything except turning on the consumed flag.
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

script for multi-threaded bash processes

hey everyone, I'm having some trouble breaking down some code. It's simple a control script that takes machines meant to be backed up from a list. Then according to that will run multi-threaded processes up until the specified thread limit. for example if there are 4 machines to be backed up,... (2 Replies)
Discussion started by: terrell
2 Replies

2. Programming

multi-threaded memory leak

Hello All : I write a .c program to test the exactually resource the memory leak as follows: 1 #include <stdio.h> 2 #define NUM 100000 3 void *Thread_Run(void * arg){ 4 //TODO 5 //pthread_datch(pthread_self()); 6 int socket= (int)arg; 7 ... (1 Reply)
Discussion started by: aobai
1 Replies

3. Linux

Multi-threaded encryption @ Fedora 11

Hello, are any of the encryption programs capable of true multi-threading ? Friend of mine tells me that he's been running some testing on Fedora 11 and that the kernel doesn't support multi-threading at that level. I've been looking into TrueCrypt, encfs and both calm to support... (1 Reply)
Discussion started by: TehOne
1 Replies

4. UNIX for Advanced & Expert Users

Multi-threaded encryption @ Fedora 11

Hello, are any of the encryption programs capable of true multi-threading ? Friend of mine tells me that he's been running some testing on Fedora 11 and that the kernel doesn't support multi-threading at that level. I've been looking into TrueCrypt, encfs and both calm to support... (0 Replies)
Discussion started by: TehOne
0 Replies

5. Shell Programming and Scripting

In need of multi threaded perl assistance

I need to write a perl script to execute external programs and grab the output and return code. Each program should be killed if it has not completed within X seconds. Imagine that the script goes something like this : @commands = &get_commands(); foreach $cmd (@commands) { $pid =... (4 Replies)
Discussion started by: SandmanCL
4 Replies

6. Programming

Questions about timer in multi-threads environment

Hi I have questions about timer function in multi-threads environment. My application has multi-threads, in one thread, I set a timer, when the timer expires, the timer function will interrupt other thread and execute. I am not clear which thread will be interrupted by the timer function ?... (2 Replies)
Discussion started by: longskys
2 Replies

7. AIX

multi threaded program is hanging

I have a Multithreaded program which is hanging on AIX. OS Version: AIX 5.2 and thread library version : 5.2.0.75 We Initiate the process with 50 threads..when we are disconnecting from the process it hangs.There is lots of other stuff involved here.I am just sending the piece of the problem with... (0 Replies)
Discussion started by: hikrishn
0 Replies

8. Programming

HOWTO: Calculate the balance of work in multi-threaded app.

I was wondering if anyone could give me a good idea how to calculate how balanced the threading is on a multi-threaded application. I want a percentage, such as "threads are 80% balanced." This is the way I am currently going about it, maybe it is good, maybe not. First, whenever a thread... (2 Replies)
Discussion started by: DreamWarrior
2 Replies

9. Programming

multi-threaded server, pthreads, sleep

I am trying to writa a multi-client & multi-threaded TCP server. There is a thread pool. Each thread in the pool will handle requests of multiple clients. But here I have a problem. I find a solution but it is not how it must be... i think. When threads working without sleep(1) I can't... (0 Replies)
Discussion started by: Parahat Melayev
0 Replies

10. Programming

problem deallocating memory for 3d aray

Can anyone tell me why this section of code causes a segmentation fault when 'deallocate' is called?. Although it works when n>=number. This code segment is intended to be used in a program in which the tensor is very large, (5x512x512) or greater. i tryed to compile this using gcc version... (2 Replies)
Discussion started by: bongobonga
2 Replies
Login or Register to Ask a Question