简体   繁体   English

创建的线程多于预期

[英]More threads created than expected

You could find the program here 你可以在这里找到这个程序

I am building a program in message passing framework 0MQ. 我正在消息传递框架0MQ中构建一个程序。 I try to implement what I posted in here 我尝试实现我在这里发布的内容

Program compiled with g++ -std=c++11 test.cpp -o test -lzmq -lpthread . 使用g++ -std=c++11 test.cpp -o test -lzmq -lpthread编译的g++ -std=c++11 test.cpp -o test -lzmq -lpthread

To run the program, pass one parameter as the thread number you would like to have. 要运行该程序,请传递一个参数作为您想要的线程号。 That parameter is then assigned to variable worker_num . 然后worker_num参数分配给变量worker_num

In main thread, I setup thread with: 在主线程中,我设置了线程:

  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));
  }

I would like to make sure all worker threads have successful connection to main thread before main thread distributes jobs to them. 我想确保所有工作线程在主线程向其分配作业之前成功连接到主线程。

  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);
    }
  }

So what main thread does is: pushing #worker_num of sync msgs with its PUSH endpoint to worker threads each time and then reads confirmation msg from its PULL endpoint. 那么主线程的作用是:每次将带有PUSH端点的sync msgs的#worker_num推送到工作线程,然后从其PULL端点读取确认消息。 If main thread retrieves #worker_num of confirmation msgs, then sync done. 如果主线程检索确认消息的#worker_num,则完成同步。 Format of the sync msg from worker is: the worker thread's ID in a string. 来自worker的同步消息的格式是:字符串中的工作线程ID。 So thread 0 would pass a 0 in string back to main thread. 因此,线程0将传递一个0的字符串返回到主线程。

But running the program I have: 但运行程序我有:

$ ./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 means thread are 2 threads created: thread 0 and thread 1. Any idea why? main thread receives sync msg from thread 1意味着线程是2线程创建:线程0和线程1.任何想法为什么? I did pass 1 as parameter. 我确实传递了1作为参数。 Noted that if you run the program yourself you may get other outputs. 注意,如果你自己运行程序,你可能会获得其他输出。

UPDATE: 更新:

Program updated: here . 程序更新: 在这里

Finally I figured out what's wrong. 最后我发现了什么是错的。

expected output, you see thread 0 pass a 0 to main thread to notify sync done: 预期输出,你看到线程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

unexpected output, you see unprintable char is passed to stoi() : 意外的输出,你看到stoi() char被传递给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

So it seems that I use message_t incorrectly. 所以我似乎错误地使用了message_t So I need to ensure that before main thread passes the content to stoi() , the buffer still exists. 所以我需要确保在主线程将内容传递给stoi() ,缓冲区仍然存在。

I will add an answer myself. 我会自己补充一个答案。

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

zmq::message_t constructor you use does not make a copy of the buffer, if [1] and [2] are to be believed. zmq::message_t使用不会使缓冲区的副本,如果构造函数[1][2]是可以相信的。 Instead, it takes ownership of the buffer. 相反,它取得了缓冲区的所有权。

However, you are passing a buffer managed by a temporary; 但是,您传递的是由临时管理的缓冲区; that buffer is destroyed as soon as the constructor returns. 一旦构造函数返回,该缓冲区就会被销毁。 You have msg_back store a dangling pointer. 你有msg_back存储一个悬空指针。 Any attempt to use that pointer - eg trying to read the message on the receiving end - exhibits undefined behavior. 任何使用该指针的尝试 - 例如尝试在接收端读取消息 - 都表现出未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM