我编写了一个在Linux C ++程序中使用线程的代码。但过了一段时间它失败了,我不知道为什么。我认为某处可能存在内存泄漏。这是一个简化版本:
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
using namespace std;
#define MAX_THREADS 20
#define THREAD_STACK 100000
pthread_t pid[MAX_THREADS];
unsigned thread_args[MAX_THREADS][2];
volatile unsigned thread_number = 0;
void* TaskCode(void* parg)
{
unsigned a = ((unsigned *)parg)[0];
unsigned b = ((unsigned *)parg)[1];
for(int i = 0; i < 1000; i++)
;
cout<< "\n\n" << a << " " << b << "\n\n";
thread_number--;
return 0;
}
void Action(unsigned long a,unsigned b)
{
if(thread_number >= MAX_THREADS)
return;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREAD_STACK);
thread_args[thread_number][0] = a;
thread_args[thread_number][1] = b;
if(pthread_create(&pid[thread_number],&attrs, TaskCode, (void*) thread_args[thread_number]) != 0)
{
cout<< "\n\n" "new thread failed. thread number:" << thread_number << "\n\n";
for(unsigned i = 0; i < thread_number; i++)
pthread_kill(pid[i], SIGSTOP);
}
thread_number++;
}
int main()
{
int a = 0;
while(true)
{
for(int i = 0; i < 1000; i++)
;
Action(time(0),1);
}
cout<< "\n\nunexpected end\n\n";
}
它有什么问题?
修改 建议我改变代码:
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
using namespace std;
#define MAX_THREADS 20
#define THREAD_STACK 100000
pthread_t pid[MAX_THREADS];
unsigned thread_args[MAX_THREADS][2];
volatile unsigned thread_number = 0;
pthread_mutex_t mutex_;
void* TaskCode(void* parg)
{
unsigned a = ((unsigned *)parg)[0];
unsigned b = ((unsigned *)parg)[1];
for(int i = 0; i < 1000; i++)
;
cout<< "\n\n" << a << " " << b << "\n\n";
pthread_mutex_lock(&mutex_);
thread_number--;
pthread_mutex_unlock(&mutex_);
return 0;
}
void Action(unsigned long a,unsigned b)
{
if(thread_number >= MAX_THREADS)
return;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, THREAD_STACK);
thread_args[thread_number][0] = a;
thread_args[thread_number][1] = b;
if(pthread_create(&pid[thread_number],&attrs, TaskCode, (void*) thread_args[thread_number]) != 0)
{
cout<< "\n\n" "new thread failed. thread number:" << thread_number << "\n\n";
for(unsigned i = 0; i < thread_number; i++)
pthread_kill(pid[i], SIGSTOP);
}
pthread_mutex_lock(&mutex_);
thread_number++;
pthread_mutex_unlock(&mutex_);
}
int main()
{
int a = 0;
pthread_mutex_init(&mutex_, NULL);
while(true)
{
for(int i = 0; i < 1000; i++)
;
Action(time(0),1);
}
pthread_mutex_destroy(&mutex_);
cout<< "\n\nunexpected endn\n";
}
仍然失败。
答案 0 :(得分:2)
你的程序以两种方式之一失败。
thread_number
由于@acarlon所指出的锁定而被破坏。如果程序运行的时间足够长(thread_number
没有被破坏),那么由于线程的产生而导致内存不足。你很快就会产生线程。退出后,你永远不会join
线程。每个线程继续驻留在内存中,直到pthread_join
被调用,以便您可以恢复它的返回码。
要验证,请在errno
失败时打印pthread_create
:
cout << "pthread_create failed:" << strerror(errno) << endl;
以上打印(如果执行的时间足够长):
pthread_create failed: Cannot allocate memory
您需要加入string.h
和errno.h
。
我注意到的第二个失败案例是thread_number
被破坏。您可以在thread_number
中打印TaskCode
来验证这一点。您会注意到有时您会获得0-20之外的值(例如4294967295)。这是@acarlon注意到的腐败。
答案 1 :(得分:2)
默认情况下,创建线程时将detachstate设置为joinable。这需要连接线程以获取线程的返回代码并清理使用的资源。
如果不清理,你会很快耗尽内存(内存泄漏)。
对于线程不需要返回任何代码并且线程退出时可以立即清理内存的情况,可以创建分离的线程。
要设置属性,以便使用pthread_attr_setdetachstate()
分离创建的所有线程。将值设置为PTHREAD_CREATE_DETACHED
。
pthread_init(&attrs);
pthread_attr_setcreatedetached(&attrs,PTHREAD_CREATE_DETACHED);
答案 2 :(得分:1)
volatile unsigned thread_number = 0;
易失性本身并不安全,您需要使用互锁增量和减量或使用thread_number周围的互斥量。易失性将保证线程不在本地缓存副本上运行。因此,如果您在一个线程上为共享变量写入值,则其他线程在读取它时将看到新值。但是,它并不能保证操作以原子方式发生。
请参阅this answer,它实际上是针对C#的,但却有正确的想法。
答案 3 :(得分:0)
感谢所有答案和评论,这是我的最终代码,我添加到存档:
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
using namespace std;
#define MAX_THREADS 20
#define THREAD_STACK 100000
pthread_t pid[MAX_THREADS];
unsigned thread_args[MAX_THREADS][3];
volatile bool pid_flags[MAX_THREADS] = {0};// all false
pthread_mutex_t mutex_;
void* TaskCode(void* parg)
{
unsigned a = ((unsigned *)parg)[0];
unsigned b = ((unsigned *)parg)[1];
unsigned index = ((unsigned*)parg)[2];
for(int i = 0; i < 1000; i++)
;
cout<< "\n\n" << a << " " << b << "\n\n";
pthread_mutex_lock(&mutex_);
pid_flags[index] = false;
pthread_mutex_unlock(&mutex_);
return 0;
}
void Sleep(unsigned milliseconds)
{
usleep(milliseconds * 1000);
}
bool FreeIndex(unsigned& index)
{
bool b;
for(index = 0; index < MAX_THREADS; index++)
{
pthread_mutex_lock(&mutex_);
b = pid_flags[index];
pthread_mutex_unlock(&mutex_);
if(b == false)
return true;
}
return false;
}
void Action(unsigned long a,unsigned b)
{
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attrs, THREAD_STACK);
unsigned free_index;
while(!FreeIndex(free_index))
Sleep(50);
thread_args[free_index][0] = a;
thread_args[free_index][1] = b;
thread_args[free_index][2] = free_index;
if(pthread_create(&pid[free_index],&attrs, TaskCode, (void*) thread_args[free_index]) != 0)
{
cout<< "\n\n" "Threading failed." "\n\n";
bool b;
for(unsigned i = 0; i < MAX_THREADS; i++)
{
pthread_mutex_lock(&mutex_);
b = pid_flags[i];
pthread_mutex_unlock(&mutex_);
if(b == true)
pthread_kill(pid[i], SIGSTOP);
}
}
pthread_mutex_lock(&mutex_);
pid_flags[free_index] = true;
pthread_mutex_unlock(&mutex_);
}
int main()
{
pthread_mutex_init(&mutex_,0);
while(true)
{
for(int i = 0; i < 1000; i++)
;
Action(time(0),1);
}
pthread_mutex_destroy(&mutex_);
cout<< "\n\n" "unexpected end" "\n\n";
}
赞赏任何改进意见。