You are not logged in.

1

Thursday, August 11th 2011, 7:48pm

use of threads to terminate an infinite loop

Hi guys,
Im have a program which outputs a sine wave with a never ending loop from the click of a pushButton. So when I click the pushButton, the sine wave gets output but the window freezes because of the never ending loop. So I am trying to thread the program and stop the loop by eliminating the thread by use of another pushButton2. I'm am having problems with this. Firstly, is threads the best way of going about fixing this problem or is there a better way. My original program is below:
Any help would be greatly appreciated

wave.cpp:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  setup() {
const char *device = "plughw:0,0";

snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_sw_params_alloca(&swparams);

int err = snd_output_stdio_attach(&output, stdout, 0);
printf( "snd_output_stdio_attach err=%d\n", err);
err = snd_pcm_open(&hspdif, device, SND_PCM_STREAM_PLAYBACK, 0);
printf( "snd_pcm_open err=%d\n", err);
err = set_hwparams(hspdif, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
printf( "set_hwparams err=%d\n", err);
err = set_swparams(hspdif, swparams);
printf( "set_swparams err=%d\n", err);

samples = new signed short [period_size * channels * snd_pcm_format_physical_width(format)];
printf( "samples array_size=%d\n", int( period_size * channels * snd_pcm_format_physical_width(format)) );

areas = new snd_pcm_channel_area_t [channels];
printf( "areas channels=%d\n", channels);
for (unsigned int chn = 0; chn < channels; chn++) {
        areas[chn].addr = samples;
        areas[chn].first = chn * snd_pcm_format_physical_width(format);
        areas[chn].step = channels * snd_pcm_format_physical_width(format);
}

}



wave::wave(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::wave)
{
ui->setupUi(this);
setup();

}

wave::~wave()
{
delete ui;

}



void wave::on_pushButton_clicked()
{
 double freq = ui->frequency->text().toDouble();
	double ampl = ui->amplitude->text().toDouble();
	double phase = 0;
	signed short *ptr;
	int err, cptr;
	while (1) {
        	generate_sine(0, period_size, &phase, freq, ampl);
        	ptr = samples;
        	cptr = period_size;
        	while (cptr > 0) {
                	err = snd_pcm_writei(hspdif, ptr, cptr);
                	if (err == -EAGAIN)
                        	continue;
                	if (err < 0) {
                        	if (xrun_recovery(hspdif, err) < 0) {
                                	printf("Write error: %s  ", snd_strerror(err));
                                	exit(EXIT_FAILURE);
                        	}
                        	break;  /* skip one period */
                	}
                	ptr += err * channels;
                	cptr -= err;
        	}
	}

}



void wave::on_pushButton_2_clicked()
{


}

Junior

Professional

  • "Junior" is male

Posts: 1,623

Location: San Antonio, TX USA

Occupation: Senior Secure Systems Engineer

  • Send private message

2

Thursday, August 11th 2011, 9:13pm

duma,

Since your using a forever loop (while(1)) the application loop event is waiting for the loop to finish before processing events. Since QApplication inherits from QCoreApplication you could first try and see if it would be disruptive within your loop to allow the application loop to process some things during it's execution using the static fx() from QCoreApplication.
(e.g. QCoreApplication::processEvents() ).

If it is to disruptive, then using a thread to basically fork off another process would be the way to go.

3

Friday, August 12th 2011, 3:24pm

duma,

Since your using a forever loop (while(1)) the application loop event is waiting for the loop to finish before processing events. Since QApplication inherits from QCoreApplication you could first try and see if it would be disruptive within your loop to allow the application loop to process some things during it's execution using the static fx() from QCoreApplication.
(e.g. QCoreApplication::processEvents() ).

If it is to disruptive, then using a thread to basically fork off another process would be the way to go.
Thanks for the suggestions, I am using threads for my function and ending the while loop by eliminating the thread with the click of another pushButton(pushButton2).
I build my code with no errors. however, when I run it, the pushButton does not generate a sine wave and I get the following message:
@QMetaObject::connectSlotsByName: No matching signal for on_write_loop(snd_pcm_t*,signed short*,snd_pcm_channel_area_t*)@

Any help would be greatly appreciated.

My code snippets are below:

wave.cpp:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void wave::on_write_loop(snd_pcm_t *handles, signed short *samples , snd_pcm_channel_area_t *areas)
{
	double freq = ui->frequency->text().toDouble();
	double ampl = ui->amplitude->text().toDouble();
	double phase = 0;
	signed short *ptr;
	int err, cptr;
	while (1) {
        	generate_sine(0, period_size, &phase, freq, ampl);
        	ptr = samples;
        	cptr = period_size;
        	while (cptr > 0) {
                	err = snd_pcm_writei(hspdif, ptr, cptr);
                	if (err == -EAGAIN)
                        	continue;
                	if (err < 0) {
                        	if (xrun_recovery(hspdif, err) < 0) {
                                	printf("Write error: %s  ", snd_strerror(err));
                                	exit(EXIT_FAILURE);
                        	}
                        	break;  /* skip one period */
                	}
                	ptr += err * channels;
                	cptr -= err;
        	}
	}

}


wave::wave(QWidget *parent) :
	QMainWindow(parent),
	ui(new Ui::wave)
{
	ui->setupUi(this);
	//setup();
	mThread = new MyThread(this);
	connect(mThread, SIGNAL(write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)), this, SLOT(on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*)));
}

wave::~wave()
{
	delete ui;

}


void wave::on_pushButton_clicked()
{

//Generate
	mThread->start();

}


void wave::on_pushButton_2_clicked()
{
//Terminate
	mThread->Stop = true;

}



wave.h:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef WAVE_H
#define WAVE_H
#include "ui_wave.h"
#include <alsa/asoundlib.h>
#include <QMainWindow>
#include <QObject>
#include "mythread.h"

namespace Ui {
	class wave;
}

class wave : public QMainWindow
{
	Q_OBJECT

public:
	explicit wave(QWidget *parent = 0);
	~wave();
	MyThread *mThread;

private slots:
	void on_pushButton_clicked();

	void on_pushButton_2_clicked();

	void setup();

private:
	Ui::wave *ui;

public slots:
	void on_write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);
;

#endif // WAVE_H


MyThread.cpp:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void MyThread::run()
{
	QMutex mutex;
	mutex.lock();
	if (this->Stop)
	mutex.unlock();

	const char *device = "plughw:0,0";

	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_sw_params_alloca(&swparams);

	int err = snd_output_stdio_attach(&output, stdout, 0);
	printf( "snd_output_stdio_attach err=%d\n", err);
	err = snd_pcm_open(&hspdif, device, SND_PCM_STREAM_PLAYBACK, 0);
	printf( "snd_pcm_open err=%d\n", err);
	err = set_hwparams(hspdif, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
	printf( "set_hwparams err=%d\n", err);
	err = set_swparams(hspdif, swparams);
	printf( "set_swparams err=%d\n", err);

	samples = new signed short [period_size * channels * snd_pcm_format_physical_width(format)];
	printf( "samples array_size=%d\n", int( period_size * channels * snd_pcm_format_physical_width(format)) );

	areas = new snd_pcm_channel_area_t [channels];
	printf( "areas channels=%d\n", channels);
	for (unsigned int chn = 0; chn < channels; chn++) {
        	areas[chn].addr = samples;
        	areas[chn].first = chn * snd_pcm_format_physical_width(format);
        	areas[chn].step = channels * snd_pcm_format_physical_width(format);
	}
	emit write_loop(hspdif, samples, areas);
}


MyThread.h:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <alsa/asoundlib.h>
#include <QThread>

class MyThread : public QThread
{
	Q_OBJECT
public:
	explicit MyThread(QObject *parent = 0);
	void run();
	bool Stop;

signals:
	void write_loop(snd_pcm_t*, signed short*, snd_pcm_channel_area_t*);

public slots:
};

#endif // MYTHREAD_H

Used tags

qt, QtCreator