创建的线程多于预期 [英] More threads created than expected

查看:102
本文介绍了创建的线程多于预期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以在此处

我正在消息传递框架0MQ中构建一个程序.我尝试实现我在此处中发布的内容>

I am building a program in message passing framework 0MQ. I try to implement what I posted in here

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

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

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.

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

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

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

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. If main thread retrieves #worker_num of confirmation msgs, then sync done. Format of the sync msg from worker is: the worker thread's ID in a string. So thread 0 would pass a 0 in string back to main thread.

但是运行我有的程序:

$ ./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作为参数.请注意,如果您自己运行该程序,则可能会得到其他输出.

main thread receives sync msg from thread 1 means thread are 2 threads created: thread 0 and thread 1. Any idea why? I did pass 1 as parameter. Noted that if you run the program yourself you may get other outputs.

程序已更新:此处.

最后我找出了问题所在.

Finally I figured out what's wrong.

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

expected output, you see thread 0 pass a 0 to main thread to notify sync done:

$ ./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() :

unexpected output, you see unprintable char is passed to 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()之前,缓冲区仍然存在.

So it seems that I use message_t incorrectly. So I need to ensure that before main thread passes the content to stoi(), the buffer still exists.

我将自己添加一个答案.

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构造函数不会复制缓冲区="nofollow noreferrer"> [1] [2 ] .取而代之的是,它获取缓冲区的所有权.

zmq::message_t constructor you use does not make a copy of the buffer, if [1] and [2] are to be believed. Instead, it takes ownership of the buffer.

但是,您正在传递由临时对象管理的缓冲区;构造函数返回后,该缓冲区即被销毁.您已经msg_back存储了一个悬空指针.任何尝试使用该指针的尝试-例如试图在接收端读取消息-表现出不确定的行为.

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. Any attempt to use that pointer - e.g. trying to read the message on the receiving end - exhibits undefined behavior.

这篇关于创建的线程多于预期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆