pthread完成后会泄漏内存

时间:2016-05-31 21:59:17

标签: c++ multithreading pthreads

我知道通过调用pthread_joinpthread_detach会释放线程完成后使用的资源,但我的情况并不那么容易。

首先,我希望能够从父线程终止子线程,所以我写了这样的东西:(动态分配的buf是为了显示我似乎找不到使用{{{ 1}}因为我不知道如何等待子线程完成(所以我可以释放buf)如果我分开它)

pthread_detach

这似乎有效。但是子线程有时会在父线程想要终止它之前完成。在这种情况下,父线程被阻止,所以

  1. 如何通知父线程子线程已终止,以便父线程可以调用bool running = true; void *foo(void *buf) { while (running) { // Do something with buf } return NULL; } int main(int argc, char **argv) { char *buf = new char[1024]; pthread_t tid; pthread_create(&tid, NULL, foo, buf); string cmd; while (true) { cin >> cmd; if (!cmd.compare("stop")) { running = false; pthread_join(tid, NULL); delete[] buf; } else { // Do something } } return 0; }

  2. 有没有办法使用pthread_join仍然可以等待子线程完成所以我可以随后释放buf(虽然看起来我可以在这个演示中的子线程中释放buf ,我的真实应用是不可能的)?

3 个答案:

答案 0 :(得分:2)

  
      
  1. 如何通知父线程子线程已终止,以便父线程可以调用pthread_join?
  2.   

有各种各样的选择。以下是三个相当有前途的方面:

  • 您可以让子线程设置一个全局标志变量。

  • 您可以让子线程通过bool SomeClass::func() { int64_t counter = 0; //some loop logic { counter++; } auto lamb = [this, &counter]() { //some logic counter++; } someotherFunction(data, lamb); // this function will execute the lambda } 向父线程发出信号。

  • 您可以设置孩子在完成时写入的管道,让父母从中执行非阻塞读取以测试孩子是否已完成。

    < / LI>
  
      
  1. 有没有办法使用pthread_detach并仍然可以等待子线程完成所以我可以随后释放buf(尽管它   似乎我可以在这个演示中的子线程中释放buf,这是不可能的   对于我的真实应用)?
  2.   

没有。一旦线程被分离,它就无法连接起来。

您可以考虑让线程管理自己的资源。或者,如果主线程必须分配资源,那么至少考虑将管理它们的责任移交给子线程。

答案 1 :(得分:0)

  

如何通知父线程子线程已终止,以便父线程可以调用pthread_join?

你考虑过使用std :: thread吗?

我认为以下代码演示了使用std :: thread无需任何操作。 sleep_for()非常适合人类观看。

void pause_thread(int n, std::string lbl)
{
  std::this_thread::sleep_for (std::chrono::seconds(n));
  std::cout << lbl << " pause of " << n << " seconds ended" << std::endl;
}

int t403(void)
{
   std::cout << "Spawning 3 threads...\n" << std::flush;
   std::thread t1 (pause_thread, 6, "t1");
   std::thread t2 (pause_thread, 3, "t2");
   std::thread t3 (pause_thread, 1, "t3");
   std::cout << "Done spawning threads, "
      "Note that they finish out-of-order. \n"
      "Now 'main' thread waits for spawned threads to join:\n" << std::flush;

   t1.join(); std::cout << "join t1  " << std::flush;
   t2.join(); std::cout << "join t2  " << std::flush;
   t3.join(); std::cout << "join t3  " << std::flush;
   std::cout << "completed join \n"
      "note: \n - join sequence is in-order, but finish sequence is out-of-order\n"
      " - inference:  the threads waited for main to join! "<< std::endl;

   return(0);
}

更新:2016年6月1日

我使用posix线程和join重现了上述方案。似乎主线程不需要通知生成的线程已终止。

另外,来自“man pthread_join”:

  

pthread_join()函数等待'thread'指定的线程   (参数1)终止。如果该线程已经终止,   然后pthread_join()立即返回。指定的线程   线程必须可以连接。

也许我对你的问题遗漏了一些东西。

发布连接的线程可能不应该在此期间尝试执行任何其他操作。

考虑将“其他任何东西”转移到自己的合作线程中?

答案 2 :(得分:0)

我将朝着不同的方向前进。问题不应该是“如何发出线程结束信号,以便我可以释放buf?”它应该是“我应该如何为buf分配所有权,最好是以线程结尾无关紧要的方式?”

foomain应该发布buf。那么哪个?

案例1:buf已分配main但未使用buf

此案例包括mainmain中分配和初始化buf只要线程处理完成后buf不消耗void *foo(void *buf) { while (running) { // Do something with buf } delete buf; return NULL; } 。这种情况很容易。线程假定buf的所有权并在线程完成时删除它。

main

案例2:foomain分配,由buf操作,然后由main使用。

main显然必须buf才能使用它,因此foo应该保留所有权并在消费后删除buf。但当?这意味着它必须等待buf完成处理foo,这意味着加入或完成消息。现在我们来看John Bollinger的答案。

案例3:foo分配在foo中,由main操作,并由buf删除。

这样做的好处是不会出现任何混淆,如果main永远不会触及 void *foo(void * ) { char buf[1024]; while (running) { // Do something with buf } return NULL; } main应完全放手,包括分配。在一个完美的世界中,这看起来像:

foo

可以向线程提供缓冲区的大小(如果pthread_create(&tid, NULL, foo, &bufsize); 已知但不知道void *foo(void * size) { char * buf = new char[*((int*)size)]; while (running) { // Do something with buf } delete buf; return NULL; } )。例如,

void *foo(void * size)
{
    std::unique_ptr<char[]> buf(new char[*((int*)size)]);
    while (running)
    {
        // Do something with buf
    }
    return NULL;
}

bufsize

但你应该更喜欢

foo

避免使用原始指针。

确保在switch3.setOnClickListener(new OnClickListener() { public void onClick(View v) { if (switch3.isChecked()) { messsage = "S"; Log.d("On", "Button On" + messsage); new Thread(new Runnable() { public void run() { // TODO Auto-generated method stub try { // client = new // Socket(etIP.getText().toString(), port); client = new Socket("192.168.4.1", 100); printwriter = new PrintWriter(client .getOutputStream(), true); printwriter.write(messsage); printwriter.flush(); //printwriter.close(); client.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } else { messsage = "T"; Log.d("off", "Button off " + messsage);// etMsg.getText().toString(); // etMsg.setText(""); // port = Integer.parseInt(etPort.getText().toString()); new Thread(new Runnable() { public void run() { // TODO Auto-generated method stub try { // client = new // Socket(etIP.getText().toString(), port); //client = new Socket("192.168.4.1", 100); printwriter = new PrintWriter(client .getOutputStream(), true); printwriter.write(messsage); printwriter.flush(); //printwriter.close(); client.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } } }); 开始之前User没有变化。

相关问题