Ir ao conteúdo
  • Cadastre-se

C++ c++ - como usar multitarefa?


Cambalinho

Posts recomendados

para usar multitarefa temos de usar a libraria: 
 

#include <pthread.h> //por exemplo
  
  // dentro de 1 classe tenho:
struct Pixel
    {
        image *img;
        float X = 0;
        float Y = 0;
        float Z = 0;
        COLORREF color = 0;

    };
    static void *DrawPixel(void *threadarg )
    {
        struct Pixel *Pix;
        Pix = (struct Pixel *) threadarg;
        //For every steps we calculate the perspective:
        //Avoiding division by zero:
        float EyeDistance = 500;// doing these i avoid the black\empty vertical lines
        const float d = EyeDistance+Pix->Z; // Note that Z==0 is irrelevant here
        const float Perspective = (d != 0) ? (EyeDistance/d) : 0;

        //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):
        int PosX = Pix->X*Perspective;
        int PosY = Pix->Y*Perspective;


        //Draw the pixel on valid positions:
        if(Pix->Z>=0 && PosX<Pix->img->Width && PosX>=0 && PosY<Pix->img->Height && PosY>=0)
        {
            size_t pixelOffset = PosY * Pix->img->scanlineSize + PosX * Pix->img->pixelSize;
            int PosR = pixelOffset+2;
            int PosG = pixelOffset+1;
            int PosB = pixelOffset+0;

            Pix->img->Pixels[PosR]=GetRValue(Pix->color);
            Pix->img->Pixels[PosG]=GetGValue(Pix->color);
            Pix->img->Pixels[PosB]=GetBValue(Pix->color);
        }
        return NULL;

    }
  //quero chamar esta função num ciclo utilizando multitarefa:
int i=0;
        pthread_t threads;
        int rc;
        do
        {

            Pixel pix{this, X,Y,Z,LineColor};
            //DrawPixel(pix);
            rc=pthread_create(&threads, NULL, DrawPixel, (void *)&pix);
            if (rc)
            {
                cout << "Error:unable to create thread," << rc << endl;

                exit(-1);
            }
            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;

            i++;
        }while(i<LineDistance);

ao fechar a janela é que vejo a mensagem de erro.
estou a fazer de forma errada?

estou a tentar usar multitarefa, mas está complicado 😞
tenho de tirar a função da classe ou isso?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

pthread.h é dos anos 90 e talvez fosse o caso de usar em C com a API do Windows.

 

Desde C++11 tem muitas outras opções. Mais simples, por exemplo usando os threads da biblioteca padrão STL.

 

Eis um exemplo

 

#include <iostream>
#include <thread>
#include <windows.h>

auto f = [](int secs) -> void { Sleep(secs); };

int main()
{
    std::thread th[8];
    for (int i = 0; i < 8; i += 1)
    {
        int milisecs = 1'000 * (1 + rand() % 5);
        std::cout << "    Disparando para " << milisecs
                  << "s\n";
        th[i] = std::thread(f, milisecs);
    };
    for (int i = 0; i < 8; i += 1)
    {
        th[i].join();
    };
    std::cout << "Todas thread terminaram\n";
    return 0;
}

 

Que mostra

 

    Disparando para 2000s
    Disparando para 3000s
    Disparando para 5000s
    Disparando para 1000s
    Disparando para 5000s
    Disparando para 5000s
    Disparando para 4000s
    Disparando para 4000s
Todas thread terminaram

 

Pode colocar qualquer código lá ou usar funções livres. Cada thread vai rodar por sua conta e o join() faz o programa esperar por eles

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

eu tentei mas sem sorte e não entendo onde errei 😞

//alterações:
void DrawPixel(void *threadarg )
    {
        struct Pixel *Pix;
        Pix = (struct Pixel *) threadarg;
        //For every steps we calculate the perspective:
        //Avoiding division by zero:
        float EyeDistance = 500;// doing these i avoid the black\empty vertical lines
        const float d = EyeDistance+Pix->Z; // Note that Z==0 is irrelevant here
        const float Perspective = (d != 0) ? (EyeDistance/d) : 0;
//...............

        int i=0;
        std::thread th;
        do
        {

            Pixel pix{this, X,Y,Z,LineColor};
            th = std::thread(this->DrawPixel, pix);
            th.join();

desculpe, mas onde errei? sim selecionei o C++17 ISO no compilador.
mas continuo com erros 😞

"||=== Build: Debug in DrawLine (compiler: GNU GCC Compiler) ===|
C:\Users\Camba\Documents\CodeBlocks\DrawLine\DrawLine.cpp||In function 'int main()':|
C:\Users\Camba\Documents\CodeBlocks\DrawLine\DrawLine.cpp|474|warning: unused variable 'TextureY' [-Wunused-variable]|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread||In instantiation of 'struct std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >':|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|127|required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (image::*)(void*); _Args = {image::Pixel&}]'|
C:\Users\Camba\Documents\CodeBlocks\DrawLine\DrawLine.cpp|228|required from here|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|240|error: no matching function for call to 'std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >::_M_invoke(std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >::_Indices)'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|231|note: candidate: 'template<long long unsigned int ..._Ind> decltype (std::__invoke((_S_declval<_Ind>)()...)) std::thread::_Invoker<_Tuple>::_M_invoke(std::_Index_tuple<_Ind ...>) [with long long unsigned int ..._Ind = {_Ind ...}; _Tuple = std::tuple<void (image::*)(void*), image::Pixel>]'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|231|note:   template argument deduction/substitution failed:|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|240|required from 'struct std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|127|required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (image::*)(void*); _Args = {image::Pixel&}]'|
C:\Users\Camba\Documents\CodeBlocks\DrawLine\DrawLine.cpp|228|required from here|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|233|error: no matching function for call to '__invoke(std::__tuple_element_t<0, std::tuple<void (image::*)(void*), image::Pixel> >, std::__tuple_element_t<1, std::tuple<void (image::*)(void*), image::Pixel> >)'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\invoke.h|89|note: candidate: 'template<class _Callable, class ... _Args> constexpr typename std::__invoke_result<_Functor, _ArgTypes>::type std::__invoke(_Callable&&, _Args&& ...)'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\invoke.h|89|note:   template argument deduction/substitution failed:|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|233|  required by substitution of 'template<long long unsigned int ..._Ind> decltype (std::__invoke(_S_declval<_Ind>()...)) std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >::_M_invoke<_Ind ...>(std::_Index_tuple<_Ind ...>) [with long long unsigned int ..._Ind = {0, 1}]'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|240|required from 'struct std::thread::_Invoker<std::tuple<void (image::*)(void*), image::Pixel> >'|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\thread|127|required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (image::*)(void*); _Args = {image::Pixel&}]'|
C:\Users\Camba\Documents\CodeBlocks\DrawLine\DrawLine.cpp|228|required from here|
C:\Program Files\CodeBlocks\MinGW\lib\gcc\x86_64-w64-mingw32\8.1.0\include\c++\bits\invoke.h|89|error: no type named 'type' in 'struct std::__invoke_result<void (image::*)(void*), image::Pixel>'|
||=== Build failed: 4 error(s), 10 warning(s) (0 minute(s), 3 second(s)) ===|"

o que me pode dizer?
 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Cambalinho não é uma questão de sorte. Sugiro que escreva programas simples até entender os métodos como join e detach e as primitivas de sincronismo. E nem toda função é "thread-safe" então precisa conhecer o que quer rodar em "multitarefa" porque pode não ser trivialmente possível

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Eu imagino qual é o meu problema: estou a usar uma função que está dentro de uma  classe.  Eu tinha feito um teste fora da classe e funciona.  Parece ser uma dor de cabeça quando queremos usar dentro das classes, como sempre é tem me acontecido. Mais logo vou testar fora da classe 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

eu já fiz o teste que funcionou, mas como disse: foi 1 função fora da classe.
para fazer 1 estrutura, que use 1 variável de classe, antes da classe criada, tenho de fazer isto, certo?
 

class NomeClass;

agora vou testar o que estava a pensar ver se resulta.

desculpe mas vamos então testar o mais simples

já noto 2 problemas, no meu teste:

#include <iostream>
#include <thread>
#include <windows.h>

struct Person
{
    int Age = 0;
    std::string Name = "";
};

auto f = [](Person Pessoa) -> void
{
    std::cout <<"Name: " << Pessoa.Name << "\n";
    std::cout << "Age: " << Pessoa.Age << "\n";
};

int main()
{
    std::thread th;
    Person Pessoa;
    Pessoa.Age=39;
    Pessoa.Name ="Joaquim";
    th = std::thread(f, Pessoa);
    for (int i = 0; i < 8; i += 1)
    {
        th.join();
    };
    std::cout << "Todas thread terminaram\n";
    return 0;
}

1 - não posso usar o 'th.join()' mais que 1 vez... porque? eu quero chamar a função quantas vezes eu preciso?
(sim a função é simples, mas imagine 1 loop de pixels)
2 - não posso usar ponteiros? porquê? sim tentei e deu erro.

ok.. estamos a começar mais simples para usar no meu código principal.

testando:
1 - tenho de usar mesmo 1 array... mesmo que fosse 1 item por cada pixel;
2 - ainda falho num membro ponteiro numa classe ou estrutura?

mas aprendi desta forma ao pesquisar:

struct Person
{
    int Age = 0;
    std::string Name = "";
    int *H;
};

Pessoa.H = new int(1000);
delete  Pessoa.H;
//ou
int *a =  new int(1000);
Pessoa.H = a;
delete  a;
//sim nunca esquecer usar, se usar 'new' temos de usar 'delete'

agora vou tentar no meu código
 

Link para o comentário
Compartilhar em outros sites

deu o mesmo problema.
voltemos ao codigo de testes:

struct test
{
    struct Person
    {
        int Age = 0;
        std::string Name = "";
        int *H;
    };

    void f(Person *Pessoa)
    {
        std::cout <<"Name: " << Pessoa->Name << "\n";
        std::cout << "Age: " << Pessoa->Age << "\n";
        std::cout << "H: " << *Pessoa->H << "\n";
    }
    
    void te()
    {
        std::thread th[100];
        Person Pessoa;
        Pessoa.Age=39;
        Pessoa.Name ="Joaquim";

        Pessoa.H = new int(1000);
        for (int i = 0; i < 100; i += 1)
        {
            th[i] = std::thread(this->f, &Pessoa);//erros
            th[i].join();

        }
        delete  Pessoa.H;

    }
};
test a;
int main()
{
    a.te();
    std::cout << "Todas thread terminaram\n";
    return 0;
}

 

a linha:
 

th[i] = std::thread(this->f, &Pessoa);//erros

dá-me imensos erros... porque estou a usar dentro de 1 estrutura... e é o mesmo erro que num classe.

então pergunto: como posso usar dentro de 1 classe?

Link para o comentário
Compartilhar em outros sites

corrigi.... e já explico como foi.

#include <iostream>
#include <thread>

struct test
{
    struct Person
    {
        int Age = 0;
        std::string Name = "";
        int *H;
    };

    void f(Person *Pessoa)
    {
        std::cout <<"Name: " << Pessoa->Name << "\n";
        std::cout << "Age: " << Pessoa->Age << "\n";
        std::cout << "H: " << *Pessoa->H << "\n";
    }

    void te()
    {
        std::thread th[1000];
        Person Pessoa;
        Pessoa.Age=39;
        Pessoa.Name ="Joaquim";


        for (int i=0; i<1000; i++)
        {
            Pessoa.H = new int(i);
            th[i] = std::thread(&test::f, this, &Pessoa);
            th[i].join();
        }


        delete  Pessoa.H;

    }
};
test a;
int main()
{
    a.te();
    std::cout << "Todas thread terminaram\n";
    return 0;
}

vamos analisar a função thread() numa classe:
 

th[i] = std::thread(&test::f, this, &Pessoa);

Parametros:
1 - o nome da função;
2 - o Parametro da função.(não sei se aceita vários argumentos).

Parametros dentro de 1 classe:
1 - endereço da função com o nome da classe: "&NomeDaClasse::NomeDaFunção";
2 - o ponteiro da classe;
3 - o parametro da função(repito, não sei aceito mais que 1).

vi 1 exemplo e tentei testar e deu.

muito obrigado

tentei usar no meu código, mas não tenho resultados e nem erros.
 

struct Pixel
    {
        image *img;
        float X = 0;
        float Y = 0;
        float Z = 0;
        COLORREF color = 0;

    };

    void DrawPixel(Pixel *Pix )
    {
        //For every steps we calculate the perspective:
        //Avoiding division by zero:
        float EyeDistance = 500;// doing these i avoid the black\empty vertical lines
        const float d = EyeDistance+Pix->Z; // Note that Z==0 is irrelevant here
        const float Perspective = (d != 0) ? (EyeDistance/d) : 0;

        //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):
        int PosX = Pix->X*Perspective;
        int PosY = Pix->Y*Perspective;


        //Draw the pixel on valid positions:
        if(Pix->Z>=0 && PosX<Pix->img->Width && PosX>=0 && PosY<Pix->img->Height && PosY>=0)
        {
            size_t pixelOffset = PosY * Pix->img->scanlineSize + PosX * Pix->img->pixelSize;
            int PosR = pixelOffset+2;
            int PosG = pixelOffset+1;
            int PosB = pixelOffset+0;

            Pix->img->Pixels[PosR]=GetRValue(Pix->color);
            Pix->img->Pixels[PosG]=GetGValue(Pix->color);
            Pix->img->Pixels[PosB]=GetBValue(Pix->color);
        }
    }

    void DrawLine(float X0, float Y0, float Z0, float X1, float Y1, float Z1, COLORREF LineColor = RGB(255,0,0))
    {
        //Getting Line Distance(float results):
        float DX = X1 - X0;
        float DY = Y1 - Y0;
        float DZ = Z1 - Z0;
        float LineDistance =sqrt((DX * DX) + (DY * DY) + (DZ * DZ));
        if(LineDistance < 1) return;


        //Getting the Steps incrementation(float results):
        float XSteps = DX/LineDistance;
        float YSteps = DY/LineDistance;
        float ZSteps = DZ/LineDistance;

        //Draw Line using the Steps\ Incrementation:
        float X = X0;
        float Y = Y0;
        float Z = Z0;

        int i=0;
        std::thread th[(int)LineDistance];
        do
        {

            Pixel *pix= new Pixel{this, X,Y,Z,LineColor};

            th[i] = std::thread(&image::DrawPixel,this, pix);
            th[i].join();
            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;

            i++;
            delete pix;
        }while(i<LineDistance);
    }

estou a testar e já sei: alterei a função e consigo ver o 'X'... significa que os dados estão a ser dados e imagino onde errei.

veja na estrutura Pixel:

struct Pixel
    {
        image *img;

agora vou perguntar: como passo o ponteiro da classe no 'img'?

pix->img = new image(*this);

 

Link para o comentário
Compartilhar em outros sites

finalmente ficou a funcionar(em vez adicionar o Multirefa ao meu codigo, devido a erros, eu adicionei a classe image ao Multitarefa):

#include <iostream>
#include <thread>
#include <windows.h>
#include <math.h>

using namespace std;
class image
{
public:
    int ImageWidth = 0;
    int ImageHeight = 0;
    HDC ImageHDC = NULL;
    HBITMAP ImageBitmap;
    HBITMAP oldBit;
    BITMAP bmp;
    BITMAPINFO info;
    size_t pixelSize;
    size_t scanlineSize;
    size_t bitmapSize;
    void* p;
    LPBYTE Pixels;


    void Clear(COLORREF BackColor = RGB(0,0,0))
    {
        RECT rec{0,0,ImageWidth,ImageHeight};
        HBRUSH HB = CreateSolidBrush(BackColor);
        FillRect(ImageHDC,&rec,HB);
        DeleteObject(HB);
    }

    image(int Width, int Height, COLORREF BackColor=RGB(0,0,0))
    {
        ImageHDC = CreateCompatibleDC(NULL);
        ImageWidth = Width;
        ImageHeight =Height;

        ZeroMemory (&info, sizeof (BITMAPINFO));
        info.bmiHeader.biSize = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth = ImageWidth;
        // pay attention to the sign, you most likely want a
        // top-down pixel array as it's easier to use
        info.bmiHeader.biHeight = -ImageHeight;
        info.bmiHeader.biPlanes = 1;
        info.bmiHeader.biBitCount = 32;
        info.bmiHeader.biCompression = BI_RGB;
        info.bmiHeader.biSizeImage = 0;
        info.bmiHeader.biXPelsPerMeter = 0;
        info.bmiHeader.biYPelsPerMeter = 0;
        info.bmiHeader.biClrUsed = 0;
        info.bmiHeader.biClrImportant = 0;

        // the following calculations work for 16/24/32 bits bitmaps
        // but assume a byte pixel array


        ImageBitmap = CreateDIBSection(ImageHDC, &info, DIB_RGB_COLORS, (LPVOID*)&Pixels, 0, 0);
        if(ImageBitmap ==NULL) cout << "no HBITMAP";
        if(SelectObject(ImageHDC, ImageBitmap)==NULL) cout << "error";
        pixelSize = info.bmiHeader.biBitCount / 8;
        // the + 3 ) & ~3 part is there to ensure that each
        // scan line is 4 byte aligned
        scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
        bitmapSize = bmp.bmHeight * scanlineSize;
        Clear(BackColor);
    }



    void NewSetPixel(HDC DestinationHDC, int X, int Y, BYTE RedColor, BYTE GreenColor, BYTE BlueColor)
    {
        size_t pixelOffset = Y *scanlineSize + X *pixelSize;
        Pixels[pixelOffset+2]=RedColor;
        Pixels[pixelOffset+1]=GreenColor;
        Pixels[pixelOffset+0]=BlueColor;
    }

    void DrawLine( float X0, float Y0, float Z0, float X1, float Y1, float Z1, COLORREF LineColor)
    {
        //Getting Line Distance(float results):
        float DX = abs(X1 - X0);
        float DY = abs(Y1 - Y0);
        float DZ = abs(Z1 - Z0);
        float LineDistance =sqrt((DX * DX) + (DY * DY) + (DZ * DZ));


        //Getting the Steps incrementation(float results):
        float XSteps = DX/LineDistance;
        float YSteps = DY/LineDistance;
        float ZSteps = DZ/LineDistance;

        //Draw Line using the Steps\ Incrementation:
        float X = X0;
        float Y = Y0;
        float Z = Z0;
        BYTE R = GetRValue(LineColor);
        BYTE G = GetGValue(LineColor);
        BYTE B = GetBValue(LineColor);
        std::thread th[(int)LineDistance+1];
        for(int i =0; i <LineDistance; i++)
        {
            //For every steps we calculate the perspective:
            float EyeDistance = 500;
            //Avoiding division by zero:
            if(Z==0) Z=1;
            float Perspective = EyeDistance/(EyeDistance+Z);

            //The 3D to 2D convertion(i use 300 of eye distance, but we can change it):

            int PosX = trunc(X*Perspective);
            int PosY = trunc(Y*Perspective);
            if(Z>=0 && PosX<ImageWidth && PosX>=0 && PosY<ImageHeight && PosY>=0)
            {
                th[i] = std::thread(&image::NewSetPixel,this,ImageHDC, PosX,PosY,R,G,B);//erros
                th[i].join();
            }

            //Increment steps(integer results):
            X+=XSteps;
            Y+=YSteps;
            Z+=ZSteps;
        }
    }

    void DrawRectangle(float PosX, float PosY, float PosZ, float Width, float Height, float Depth, COLORREF Color = RGB(255,0,0), bool Filled = false)
    {
        DrawLine( PosX, PosY, PosZ,PosX + Width, PosY, PosZ + Depth, Color);
        DrawLine( PosX, PosY, PosZ, PosX, PosY + Height, PosZ, Color);
        DrawLine( PosX + Width, PosY, PosZ + Depth, PosX + Width, PosY+Height, PosZ + Depth, Color);
        DrawLine( PosX, PosY + Height, PosZ, PosX + Width, PosY + Height, PosZ + Depth, Color);
        if(Filled==true)
        {
            for(int i = 0; i<Height; i++)
                DrawLine( PosX, PosY + i, PosZ,PosX + Width, PosY +i, PosZ + Depth, Color);

        }
    }

    ~image()
    {
        SelectObject(ImageHDC, oldBit);
        DeleteObject(ImageBitmap);
        DeleteDC(ImageHDC);
    }

};

image img(200,200);

int main()
{
    img.DrawRectangle(0,100,0, 100,100,500, RGB(255,0,0),true);
    BitBlt(GetWindowDC(GetConsoleWindow()),10,100,img.ImageWidth,img.ImageHeight,img.ImageHDC,0,0,SRCCOPY);

    return 0;
}

mas ficou mais lento do que sem usar Multitarefa... porque?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!