Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

libinha

Threads Visual c++

Recommended Posts

libinha

Ola! :D

Neste momento estou a desenvolver uma interface em visual c++ para comunicar com diversos sensores. Deparei-me com um pequeno problema. Para poder receber dados de diversos sensores, eu tenho de desenvolver um programa que receba dados dos mesmos ao mesmo tempo, isto é, em paralelo. Isto é feito com Threads certo?Será que me podiam dar uma ajuda global de como isso pode ser feito?onde declarar as funcoes que quero usar?Do que encontro no google nada me clarifica muito bem.

Obrigada! :bye2:

Share this post


Link to post
Share on other sites
TheDark

BackgorundWorker é uma facilidade da plataforma .net. Só se estiveres a utilizar C++/CLI é que podes utilizar isso.

Se for C++ "puro", dá um pouco mais de trabalho.

Vou dar um exemplo de um programa que cria duas threads e fica à espera que elas terminem. Atenção que este código é específico para Windows.

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

const int n_threads = 2;

using namespace std;

class thParams {	/* Classe para enviar parâmetros à função da thread */
public:
const char *str;
int nr;
thParams(const char *_str, const int _nr): str(_str), nr(_nr) {}
};

DWORD WINAPI threadFunc1(LPVOID parameter) {
cout << "Sou a thread 1 e vou dormir 10 segundos!\n";
Sleep(10000);
return 0;
}

DWORD WINAPI threadFunc2(LPVOID parameter) {
thParams *parms = (thParams*)parameter;
cout << "Sou a thread 2, recebi a string \"" << parms->str << "\" e o inteiro " << parms->nr << " e vou dormir 5 segundos!\n";
Sleep(5000);
return 0;
}

int main(void) {
HANDLE threads[n_threads];

thParams *par = new thParams("Frase para escrever", 10);

/* Criar duas threads, uma com inicio na função threadFunc1, sem receber parâmetros */
threads[0] = CreateThread(NULL, 0, threadFunc1, NULL, 0, NULL);
/* e outra com a threadFunc2, que receberá como parâmetro uma classe thParams */
threads[1] = CreateThread(NULL, 0, threadFunc2, (LPVOID)par, 0, NULL);

/* Esperar que todas as threads terminem */
WaitForMultipleObjects(n_threads, threads, TRUE, INFINITE);

return 0;
}

Este código não faz qualquer verificação de erros, o que é mau.

Tens mais informação aqui, e qualquer dúvida, pergunta.


Desaparecido.

Share this post


Link to post
Share on other sites
libinha

Por exemplo na minha interface. Eu tenho um botao de connect e outro de disconnect para cada sensor. Quando carrego no connect ele vai para um thread que tem as funcoes relativas à comunicacao com a serial port e fica aí até carregar no disconnect onde coloca a funcao exitthread, certo?

Depois no connect do outro sensor, ao mesmo tempo, faco exactamente o mesmo...podendo aceder às mesmas funcoes?

Nao sei o que colocar no lpParam???penso que ainda nao percebi bem o uso das threads?Alguem consegue entender qual é o meu problema?

Estou a necessitar urgentemente de ajuda neste tópico.

E já agora!será mais fácil fazer a minha GUI utilizando o Qt no C++.

Mais uma vez muito obrigada pela ajuda

Share this post


Link to post
Share on other sites
TheDark

Não sei se percebi bem a dúvida, mas podes utilizar a mesma função para mais que uma thread.

O lpParam serve para enviar parâmetros para as threads. No teu caso, por exemplo, se tens um botão para ligar ao COM1, e outro para o COM2, poderias fazer o seguinte:

class ComPort {
    int number;
}

HANDLE threads[10];
/* volatile para que seja sempre lido o seu valor da memória e não da cache */
volatile bool StopReadingComPort[10];

/* ... */

DWORD WINAPI thReadComPort(LPVOID cp) {
    ComPort *com_port = (ComPort)cp;

    cout << "Vou ler a porta COM numero " << com_port->number << endl;

    /* salvaguardar partilha de StopReadingComPort[com_port->number] */
    while (StopReadingComPort[com_port->number] == false) {
        /* parar salvaguarda da partilha porque a variável já foi lida */
        /* ler porta com */
        /* salvaguardar partilha de StopReadingComPort[com_port->number] para o próximo ciclo*/
    }
    /* parar salvaguarda da partilha do último ciclo */
    return 0;
}

/* ... */

void btReadCom1Pressed() { /* funcao chamada quando e pressionado o botao da COM1 */
    ComPort *com_port = new ComPort();

    com_port.number = 1;

    /* criar uma thread com a função thReadComPort e passar-lhe com_port como
       argumento de forma a que a função saiba qual a porta COM a ler */
    threads[0] = CreateThread(NULL, 0, thReadComPort, (LPVOID)com_port, 0, NULL);
}

void btReadCom2Pressed() { /* funcao chamada quando e pressionado o botao da COM2 */
    ComPort *com_port = new ComPort();

    com_port.number = 2;

    /* criar uma thread com a função thReadComPort e passar-lhe com_port como
       argumento de forma a que a função saiba qual a porta COM a ler */
    threads[1] = CreateThread(NULL, 0, thReadComPort, (LPVOID)com_port, 0, NULL);
}

void btStopCom1Pressed() { /* funcao chamada quando e pressionado o botao para parar de ler da COM1 */
    /* salvaguardar consistência de dados de StopReadingComPort[0] */
    StopReadingComPort[0] = true;
    /* parar salvaguarda da partilha porque a variável já foi escrita */
}

int main(void) {
    // (...)
    for (int i = 0; i< 10; ++i) StopReadingComPort[i] = false;
    // (...)

Utilizar múltiplas threads não é uma coisa trivial, principalmente se tiveres que partilhar dados entre elas, que é o que terás que fazer para saber se o botão para parar de ler foi pressionado na função thReadComPort. Nesse caso terias que utilizar critical sections, ou monitores, ou mutexes, ou alguma outra forma de garantir que a partilha de dados não iria constituir problema.

Não testei nenhum do código acima, e sei que isto pode parecer brutal. A verdade é que até é. Multithreading não é pêra doce, pelo menos ao início. Também ainda não sei se eventualmente melhora ::D


Desaparecido.

Share this post


Link to post
Share on other sites
libinha

Obrigada, Já deu para satisfazer algumas das dúvidas que tinha. Vou tentar implementar e depois se tiver mais dúvidas venho até aqui.

Obrigada

Share this post


Link to post
Share on other sites
libinha

Tentei implementar a thread mas obtenho sempre o mesmo erro com a funcao AfxBeginThread.

Erro:

Error 70 error C3867: 'CUAV_ProjectDlg::threadReadData': function call missing argument list; use '&CUAV_ProjectDlg::threadReadData' to create a pointer to member.

A funcao readdata tem de ser definida em algum lugar especifico?

Obrigada

Share this post


Link to post
Share on other sites
TheDark

Pelo que percebi do erro, faltam os argumentos na chamada à função. Isso é um projecto MFC? Podes mostrar o código onde está a dar o erro?


Desaparecido.

Share this post


Link to post
Share on other sites
libinha

Sim é MFC. Eu estou a fazer tudo de novo...penso que o problema está nos parametros da funcao. Vou tentar de novo e se nao consigo mando entao o código. Que desespero!!!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.