我必须从thread A
向所有线程threads B-1
发送少量数据(~1k字节)到threads B-n
。
我目前的实施相当复杂:
使用GHashTable
将队列映射到thread id
。通过threads B-x
和GCond
将所有g_cond_wait(_until)
置于等待状态。将指向所有线程的数据的指针推送到thread A
的每个队列中,通过g_cond_broadcast
广播更新(它们都使用相同的GCond
实例)。
如果线程决定完成(即远程DC),首先从GHashTable
中删除队列,清除队列并销毁内容。我遗漏了一些细节(比如竞争条件,等待区周围的中间参考/不足)。
这是一种理智的方法吗?我怎样才能改善这一点。它根本没有“感觉”效率。
仅供参考,附上一些草案代码:
typedef struct {
//TODO verify this is not too stupid
// if we use that mutex too often, all parallel foo is pointless
GMutex mutex;
GHashTable *hashmap; //full of queues
gint refs;
GDestroyNotify fx_ref;
GDestroyNotify fx_unref;
} Foo;
Foo *
foo_new (GDestroyNotify fx_ref, GDestroyNotify fx_unref)
{
Foo *foo;
foo = g_new0 (Foo, 1);
g_assert (foo);
g_mutex_init (&(foo->mutex));
foo->hashmap = g_hash_table_new_full ();
foo->refs = 1;
foo->fx_ref = fx_ref; //just asume this increases the refcount atomically
foo->fx_unref = fx_unref; //"" decreases ""
return foo;
}
void
foo_register_thread (Foo *obj, gint threadid)
{
AQueue *aq;
foo_lock (obj);
aq = a_queue_new ((GDestroyNotify)i_do_unref);
g_hash_table_insert (obj->hashmap, id, aq);
foo_unlock (obj);
}
void
foo_unregister_thread (Foo *obj, gint threadid)
{
AQueue *aq;
foo_lock (obj);
g_hash_table_remove (obj->hashmap, id);
// broadcast _after_ removing the queue from the hashtable,
// so the thread wakes up and quits its foo_thread_wait_until_ready call
g_cond_broadcast (obj->cond);
foo_unlock (obj);
// allow somebody to sneak in
foo_lock (obj);
a_queue_unref (aq)
foo_unlock (obj);
}
void
foo_enqueue (Foo *obj, gpointer data)
{
GHashTableIter iter;
gint key;
GAsyncQueue *queue;
//wave after wave, not wave intermixing
g_mutex_lock (&obj->mutex);
g_hash_table_iter_init (iter, obj->ht);
while (g_hash_table_iter_next (&iter, &id, &queue)) {
if (foo->fx_ref)
foo->fx_ref (data);
g_queue_push_tail (queue, data);
}
g_cond_broadcast (cond);
g_mutex_unlock (&obj->mutex);
}
gpointer
foo_thread_pop (Foo *obj, gint id)
{
AQueue *aq;
gpointer data = NULL;
g_return_val_if_fail (obj, NULL);
g_return_val_if_fail (id>0, NULL);
foo_lock (obj);
aq = g_hash_table_lookup (obj->hashmap, id);
if (aq) {
data = g_queue_pop_head ((GQueue*)aq);
}
foo_unlock (obj);
return data;
}
/**
* wait until the queue gets removed or until data is ready to be read
*/
gpointer
foo_thread_wait_until_ready (Foo *obj, gint id)
{
gpointer data = NULL;
AQueue *aq;
foo_lock (obj);
aq = (AQueue*)g_hash_table_lookup (obj->hashmap, id);
if (!aq)
return NULL;
// just in case stuff gets cleaned up in the meantime
a_queue_ref (aq);
while (g_queue_peek_head ((GQueue*)aq)==NULL) {
g_cond_wait_until (&(obj->cond), &(obj->mutex))
// make sure queue still exists, if not this means this thread is dying
if (g_hash_table_lookup (obj->hashmap, id) != (gpointer)aq)
break;
}
data = g_queue_pop_head ((GQueue*)aq);
a_queue_unref (aq);
foo_unlock (obj);
return data;
}
void
foo_destroy (Foo *obj)
{
g_return_if_fail (obj);
g_mutex_clear (&obj->mutex);
g_cond_clear (&obj->cond);
}
void
foo_unref (Foo *obj)
{
g_return_if_fail (obj);
if (g_atomic_int_dec_and_test (&obj->refs))
foo_destroy (obj);
}
void
foo_ref (Foo *obj)
{
g_return_if_fail (obj);
g_atomic_int_inc (&obj->refs);
}
void
foo_lock (Foo *obj)
{
g_return_if_fail (obj);
g_atomic_int_inc (&obj->refs);
g_mutex_lock (&obj->mutex);
}
void
foo_unlock (Foo *obj)
{
g_return_if_fail (obj);
g_mutex_unlock (&obj->mutex);
foo_unref (obj);
}
答案 0 :(得分:0)
我使用fork做了类似的事情。以下是该算法的高级概述:
假设:每个线程不需要向父节点广播回内存。每个请求都可以按任何顺序处理。
然后每个叉子如下:
父母只是等待所有线程完成。