我知道通过调用pthread_join
或pthread_detach
会释放线程完成后使用的资源,但我的情况并不那么容易。
首先,我希望能够从父线程终止子线程,所以我写了这样的东西:(动态分配的buf是为了显示我似乎找不到使用{{{ 1}}因为我不知道如何等待子线程完成(所以我可以释放buf)如果我分开它)
pthread_detach
这似乎有效。但是子线程有时会在父线程想要终止它之前完成。在这种情况下,父线程被阻止,所以
如何通知父线程子线程已终止,以便父线程可以调用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;
}
?
有没有办法使用pthread_join
仍然可以等待子线程完成所以我可以随后释放buf(虽然看起来我可以在这个演示中的子线程中释放buf ,我的真实应用是不可能的)?
答案 0 :(得分:2)
- 如何通知父线程子线程已终止,以便父线程可以调用pthread_join?
醇>
有各种各样的选择。以下是三个相当有前途的方面:
您可以让子线程设置一个全局标志变量。
您可以让子线程通过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>
- 有没有办法使用pthread_detach并仍然可以等待子线程完成所以我可以随后释放buf(尽管它 似乎我可以在这个演示中的子线程中释放buf,这是不可能的 对于我的真实应用)?
醇>
没有。一旦线程被分离,它就无法连接起来。
您可以考虑让线程管理自己的资源。或者,如果主线程必须分配资源,那么至少考虑将管理它们的责任移交给子线程。
答案 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
分配所有权,最好是以线程结尾无关紧要的方式?”
foo
或main
应该发布buf
。那么哪个?
案例1:buf
已分配main
但未使用buf
此案例包括main
在main
中分配和初始化buf
只要线程处理完成后buf
不消耗void *foo(void *buf)
{
while (running)
{
// Do something with buf
}
delete buf;
return NULL;
}
。这种情况很容易。线程假定buf
的所有权并在线程完成时删除它。
main
案例2:foo
由main
分配,由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
没有变化。