开发者

C Parallel Garbage Collector, how to avoid locking out main thread

开发者 https://www.devze.com 2023-03-26 02:44 出处:网络
I a开发者_如何转开发m developing a parallel garbage collector. It is a tri-marking collector that does the usual white->grey->black. When the collector moves an object from grey to black it descends i

I a开发者_如何转开发m developing a parallel garbage collector. It is a tri-marking collector that does the usual white->grey->black. When the collector moves an object from grey to black it descends into the object in order to mark the children grey. At this time it needs to take out a lock in order to prevent the object from changing in the main thread while the object is being read. Since it would be an insane memory requirement to give each object an independant lock, I have a single lock (per non-gc thread) that must be locked before modifying an object. The GC will use that threads lock before reading the object.

So, the GC will be iterating objects from a thread and taking out a lock before reading children, then releasing the lock before the next iteration. I want to make sure the GC does not hog the lock to much. To me the obvious solution seems to be a 'yield' just after releasing the lock so that the main thread may continue if it is waiting on the lock. The garbage collector is not a priority thread, it doesn't matter if it takes a long time to get its work done.

However, I am using pthreads (linux), and when I google the sched_yield() function I find that it is considered harmful. Most of the results are an argument over what it should even be doing. In short it seems it can be argued that if your using sched_yield() you are doing something wrong.

http://www.technovelty.org/code/c/sched_yield.html seems to propose an alternative, but I am having trouble grasping the key point of the algorithm, or specifically how to apply it to my needs.


On the subject of having a per-object lock, one approach I've used to keep the space requirements constrained is to have a circular array of locks (with some large but manageable number of locks in it, like say 8096). Then you put some arbiter in front of it that associates a given object with the next lock in the array (or if the object is already associated with a lock in the array, then the arbiter promotes that lock back to the front of the array).

This gives you the performance benefits of keeping a separate lock for each object, without the insane space requirements of actually having a distinct lock object for every distinct object instance. Of course, you'll have to tune the number of locks to your algorithm to ensure that the time it takes to cycle through the entire circular array of locks is always less than the amount of time required to process an object.

Or maybe a better approach would be to have the arbiter work more like a resource-manager for a pool of locks that get "checked out" and "checked in". Then when someone requests to check out a lock the arbiter can immediately issue one so long as one is available in the pool (or already checked out for the same object instance), or otherwise it has to block until some other thread checks a lock back in.

Anyways, I'm not sure if this is directly applicable to your question, I just wanted to point out that there are other workable options in between "one lock for every object" and "only one lock ever" that may be useful within your usage model.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号