使线程同时失败之后(Making threads fails after a while)

2019-10-19 17:40发布

我写了使用的线程在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";
}

但仍然是失败。

Answer 1:

默认情况下,线程与detachstate设置为可连接创建。 这就要求线结合,以获得一个线程和清理使用的资源的返回码。

没有清理你会耗尽内存真的很快(内存泄漏)。

对于那些线程需要不返回任何代码的内存清理的情况下能够尽快线程退出,可以创建,然后分离的线程来完成。

要设置这样创建的所有线程将被分开使用属性pthread_attr_setdetachstate() 将该值设置为PTHREAD_CREATE_DETACHED

pthread_init(&attrs);
pthread_attr_setcreatedetached(&attrs,PTHREAD_CREATE_DETACHED);


Answer 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.herrno.h

我注意到第二次失败的情况是thread_number被损坏。 您可以通过打印验证这thread_numberTaskCode 。 你会注意到,你有时会值0-20外(4294967295为例)。 这是@acarlon指出腐败。



Answer 3:

 volatile unsigned thread_number = 0;

挥发性对自己是不是安全的,你需要使用互锁递增和递减或使用互斥体周围的thread_number。 挥发性将保证线程不会在本地缓存副本操作。 所以,如果你写在一个线程中的值共享变量,其他线程将看到新的价值,当他们读它。 然而,这并不能保证原子发生的操作。

见这个答案 ,这实际上是C#,但有正确的观念。



Answer 4:

感谢所有的答案和评论,这是我最后的代码,我添加到压缩文件:

#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";
}

任何改进意见表示赞赏。



文章来源: Making threads fails after a while