创建的线程多于预期

时间:2017-05-30 12:49:41

标签: c++ multithreading c++11 concurrency zeromq

您可以找到程序here

我正在消息传递框架0MQ中构建一个程序。我尝试实施我在here

中发布的内容

使用g++ -std=c++11 test.cpp -o test -lzmq -lpthread编译的程序。

要运行程序,请传递一个参数作为您想要的线程号。然后将该参数分配给变量worker_num

在主线程中,我使用以下命令设置线程:

  vector<thread> pool;
  for(int i = 0; i < worker_num; i++)
  {
    cout << "main() : creating thread, " << i << endl;
    pool.push_back(thread(task1, (void *)&context, i));
  }

我想确保在主线程向其分配作业之前,所有工作线程都已成功连接到主线程。

  while(true)
  {
    if(sync_done)
    {
      cout << "sync done in main thread" << endl;
      break;
    }

    zmq::message_t sync_msg(4);
    memcpy((void *)sync_msg.data(), SYNC_MSG, SYNC_MSGLEN);
    for(int i = 0; i < worker_num; i++)
      distask_socket.send(sync_msg);

    for(int i = 0; i < worker_num; i++)
    {
      if(sync_done)
        break;
      if(i != 0)
        this_thread::sleep_for(chrono::milliseconds(500));

      zmq::message_t res_msg;
      int ret = getres_socket.recv(&res_msg, ZMQ_DONTWAIT);

      if(ret == -1 && errno == EAGAIN)
        continue;

      int threadID = stoi(string((char *)res_msg.data()));
      sync_done = if_sync_done(threadID, sync_array, worker_num);
    }
  }

所以主线程的作用是:每次将带有PUSH端点的sync msgs的#worker_num推送到工作线程,然后从其PULL端点读取确认消息。如果主线程检索确认消息的#worker_num,则完成同步。来自worker的同步消息的格式是:字符串中的工作线程ID。因此,线程0会将字符串中的0传递回主线程。

但是运行我的程序:

$ ./test 1
main() : creating thread, 0
thread id:0
thread 0 receives: sync
thread 0 sends: 0
thread 0 sync done
main thread receives sync msg from thread 1 # you may get many copies of this msg
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoi
Aborted

main thread receives sync msg from thread 1表示线程是2线程创建的:线程0和线程1.知道为什么?我确实传递了1作为参数。注意,如果你自己运行程序,你可能会获得其他输出。

UPDATE:

计划已更新:here

最后我发现了什么是错的。

预期输出,您会看到线程0将0传递给主线程以通知已完成同步:

$ ./test 1
input parameter is: 1
main() : creating thread, 0
thread 0 receives: sync
to_string 0
thread 0 sends: 0, with size: 1
thread 0 sync done
pass 0 to if_sync_done
main thread receives sync msg from thread 0
sync done in main thread

意外输出,您会看到不可打印的字符传递给 stoi()

$ ./test 1
input parameter is: 1
main() : creating thread, 0
thread 0 receives: sync
to_string 0
thread 0 sends: 0, with size: 1
thread 0 sync done
pass  to if_sync_done  # !!!!!
terminate called after throwing an instance of 'std::invalid_argument'
  what():  stoi
Aborted

所以我似乎错误地使用了message_t。所以我需要确保在主线程将内容传递给stoi()之前,缓冲区仍然存在。

我会自己添加一个答案。

1 个答案:

答案 0 :(得分:2)

zmq::message_t msg_back((void *)to_string(id).c_str(), to_string(id).size() + 1, NULL);
您使用的

zmq::message_t构造函数制作缓冲区的副本,如果要相信[1][2]。相反,它取得了缓冲区的所有权。

但是,您传递的是由临时管理的缓冲区;一旦构造函数返回,该缓冲区就会被销毁。你有msg_back存储一个悬空指针。任何使用该指针的尝试 - 例如试图在接收端读取消息 - 表现出未定义的行为。