如何从Vala中的不同Thread添加到GLib.List

时间:2014-11-26 20:50:24

标签: multithreading glib vala

我有一个我要添加元素的GLib.List 我想使用多个GLib.Threads

同时添加这些元素

我尝试使用GLib.Mutex同步对列表的访问。同步似乎有效,但没有添加任何元素。

public static void main() {
    var list = new GLib.List<string>();
    var mutex = GLib.Mutex();

    var workerA = new Worker("A", list, mutex);
    var workerB = new Worker("B", list, mutex);
    var workerC = new Worker("C", list, mutex);

    GLib.Thread<void*> tA = new GLib.Thread<void*>("WorkerThread", workerA.run);
    GLib.Thread<void*> tB = new GLib.Thread<void*>("WorkerThread", workerB.run);
    GLib.Thread<void*> tC = new GLib.Thread<void*>("WorkerThread", workerC.run);

    tA.join();
    tB.join();
    tC.join();

    stdout.printf("List:\n");
    foreach (string str in list) {
        stdout.printf(" - %s\n", str);
    }
}

class Worker : GLib.Object {
    private string name;
    private weak GLib.List<string> list;
    private weak GLib.Mutex mutex;

    public Worker(string name, GLib.List<string> list, GLib.Mutex mutex) {
        this.name = name;
        this.list = list;
        this.mutex = mutex;
    }

    public void* run() {
        mutex.lock();
        list.append(name);
        mutex.unlock();

        return null;
    }
}

当我查看同步部分时,它似乎工作正常(即使有更多的线程),但没有元素被添加到列表中!

输出:

  

列表:

有人可以告诉我怎么做吗?

2 个答案:

答案 0 :(得分:1)

GLib.List有点奇怪。 append方法实际上修改了指针list,而不是它指向的东西。如果你想要这个,你需要:

  1. 将列表放在共享位置(例如,使其成为所有线程共享的类的字段或全局变量)。
  2. 使用libgee包中的Gee.List代替。一般来说,在vala中的数据结构比在glib中的对应部分更容易在Vala中使用。

答案 1 :(得分:0)

感谢 apmasell 指出不起作用的事实上是GLib.List我看了C source code

他是对的:如果append为空,GLib.List方法会修改指针 - 但仅(!)! 因此,除了使列表成为全局变量或使用其他列表实现之外,我认为最好的工作方法是在将列表传递给线程之前简单地添加一个元素。
完成所有线程后,您只需再次删除该元素即可。