向中间工作人员发送消息时,工作人员未完成

时间:2015-01-24 17:47:15

标签: multithreading concurrency d

我正在使用"在D&#34中编程;了解D语言。我写了一个简单的程序,它生成一个worker并发送一个数字来接收它作为字符串的正方形。 worker 1得到数字并将其发送给worker 2(一个不同的函数)以获得作为字符串的字符串,该字符串返回给worker 1,因此它将它返回给main函数调用。我可以在一个线程中写出整个事情。我写这篇文章是为了更好地了解工人。我使用receive让工作者1根据输入行事。该计划如下

import std.stdio;
import std.concurrency;
import std.conv;
import core.thread;

void main() {

  foreach (int num; 1..100) {
    auto square_tid = spawn(&square);
    square_tid.send(num);
    auto square = receiveOnly!string();
    writeln(square);
  }
}


void square() {
  static i = 0;
  receive (
       (int num) {
         auto square = num * num;
         writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
         auto stringWorker = spawn(&stringConverter);
         stringWorker.send(thisTid, square, ownerTid);
       },
       (Tid tid, string str) {
         writeln("comes in string");
         send(tid, "hello");
       });
}

void stringConverter() {
  static i = 0;
  auto params = receiveOnly!(Tid, int, Tid)();
  auto stringified = to!string(params[1]); // Stringify the square
  writeln("string : Comes in with " , params[1], " for " , ++i , " time");
  params[0].send(params[2], stringified); // params[0] - square function tid, params[2] - main function tid
}

我可以收到主函数tid并直接发回字符串。但是当我回到工人1时,它会受到打击并且不会继续进行。如何使线程从主线程和从线程接收输入。关于线程的另外几个问题:

  • 如果我想将-1作为数据发送给我的工作人员而不退出它。我该怎么办?
  • 在整个过程中使用单个worker是否可以,或者我可以像在foreach循环中一样使用多个worker?
  • 本书使用以下代码。为什么它在代码中显然具有值> = 0。


    import std.stdio;
    import std.concurrency;
    import std.conv;

    void main() {
      Tid worker = spawn(&workerFunc);
      foreach (value; 1 .. 5) {
        worker.send(value);
        double result = receiveOnly!double();
        writefln("sent: %s, received: %s", value, result);
      }
      /* Sending a negative value to the worker so that it
       * terminates. */
      worker.send(-1);
    }

    void workerFunc() {
      int value = 0;
      while (value >= 0) {
        value = receiveOnly!int();
        double result = to!double(value) / 5;
        ownerTid.send(result);
      }
    }

如果我在任何术语中出错,请纠正我。

1 个答案:

答案 0 :(得分:1)

对于这种任务,最好使用std.parallelism

import std.stdio;
import std.parallelism;

void main() {
    auto squares = new long[100];
    foreach(i, ref elem; parallel(squares)) {
        elem = i * i;
    }

    writeln(squares);
}

将-1发送到工作线程没有问题,只有在明确询问时才会退出线程。

以下是您尝试的修改版本:

import std.stdio;
import std.concurrency;
import std.conv;

void main() {

    foreach (int num; 1..100) {
        auto square_tid = spawn(&square);
        square_tid.send(num);
        auto square = receiveOnly!string();
        writeln(square);
    }
}


void square() {
    static shared i = 0;
    receive (
        (int num) {
        int square = num * num;
        writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
        auto stringWorker = spawn(&stringConverter);
        stringWorker.send(thisTid, square, ownerTid);
        receive ((Tid tid, string str) { writeln("comes in string"); send(tid, "hello");});
    });
}

void stringConverter() {
    static shared i = 0;
    auto params = receiveOnly!(Tid, int, Tid)();
    auto stringified = to!string(params[1]); // Stringify the square
    writeln("string : Comes in with " , params[1], " for " , ++i , " time");
    params[0].send(params[2], stringified); // params[0] - square function tid, params[2] - main function tid
}

更新说明

代码中的square函数在receive之后结束。因此,它永远不会尝试使用(Tid tid, string str)部分的下一个块。这就是为什么我把它放在receive的第一部分。

每次调用spawn都会创建新线程。由于D默认使用TLS,因此static关键字在您的示例中无用。因为在每个新帖子中i都是0。这就是我使用shared关键字的原因。

更新2

这是一个可以解释更多工作原理的版本:

import std.stdio;
import std.concurrency;
import std.conv;

void main() {

    foreach (int num; 1..100) {
        auto square_tid = spawn(&square);
        square_tid.send(num);
        auto square = receiveOnly!string();
        writeln(square);
    }
}


void square() {
    shared static i = 0;
    bool end = false;
    while(!end) receive (
        (int num) {
        auto square = num * num;
        writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
        auto stringWorker = spawn(&stringConverter);
        stringWorker.send(square);
    },
    (string str) {
        writeln("comes in string");
        ownerTid.send(str);
        end = true;
    });
}

void stringConverter() {
    shared static i = 0;
    auto params = receiveOnly!(int)();
    auto stringified = to!string(params); // Stringify the square
    writeln("string : Comes in with " , params, " for " , ++i , " time");
    ownerTid.send(stringified); // params[0] - square function tid, params[2] - main function tid
}