I'm trying to code a 16 bit ALU that has the components of an Arithmetic Unit, Logic Unit, Shifter Unit, a controller.
When I try and run simulation I get these errors.
Vivado Commandslaunch_simulation
[USF-XSim-62] 'elaborate' step failed with error(s). Please check the Tcl console output or 'C:/Users/Gzuz/Desktop/FinalProject/FinalProject.sim/sim_1/behav/xsim/elaborate.log' file for more information.
[Vivado 12-4473] Detected error while running simulation. Please correct the issue and retry this operation.
Simulationsim_1[VRFC 10-664] expression has 3 elements ; expected 16 ["C:/Users/Gzuz/Desktop/FinalProject/FinalProject.srcs/sources_1/new/ALU16bit.vhd":54]
[XSIM 43-3321] Static elaboration of top level VHDL design unit alu_tb in library work failed.
What I'm I doing wrong? How can I get this to run simulation.I have been trying to fix the code for hours but have had no luck, so any help is appreciated.
--VHDL CODE--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.LogicUnit16Bit;
use work.ArithmeticUnit16bit;
use work.Shift;
use work.MUX_4_TO_1;
use work.ALUControler;
entity ALU16bit is
Port ( A : in STD_LOGIC_VECTOR(15 downto 0);
B : in STD_LOGIC_VECTOR(15 downto 0);
Opcode : in STD_LOGIC_VECTOR(2 downto 0);
Mode : in STD_LOGIC;
ALUout : out STD_LOGIC_VECTOR(15 downto 0);
Cout : out STD_LOGIC);
end ALU16bit;
architecture Behavioral of ALU16bit is
component ArithmeticUnit16bit is
Port ( A : in STD_LOGIC_VECTOR(15 downto 0);
B : in STD_LOGIC_VECTOR(15 downto 0);
Op_Sel : in STD_LOGIC_VECTOR(1 downto 0);
ArithOut : out STD_LOGIC_VECTOR(15 downto 0);
Cout : out STD_LOGIC);
end component;
component LogicUnit16Bit is
Port ( A : in STD_LOGIC_VECTOR(15 downto 0);
B : in STD_LOGIC_VECTOR(15 downto 0);
OpCode : in STD_LOGIC_VECTOR(2 downto 0);
LogicOut : out STD_LOGIC_VECTOR(15 downto 0));
end component;
component Shift is
Port ( A : in STD_LOGIC_VECTOR(15 downto 0);
B : in STD_LOGIC_VECTOR(15 downto 0);
Direction: in STD_LOGIC;
Op_Type: in STD_LOGIC;
ShiftOut : out STD_LOGIC_VECTOR(15 downto 0));
end component;
component MUX_4_TO_1 is
Port (Ain,Bin,Cin,Din: in STD_LOGIC_VECTOR(15 downto 0);
Sel:in STD_LOGIC_VECTOR(1 downto 0);
Zout: out STD_LOGIC_VECTOR( 15 downto 0));
end component;
component ALUControler is
Port ( Mode : in STD_LOGIC;
Opcode : in STD_LOGIC_VECTOR(2 downto 0);
Op_out : out STD_LOGIC_VECTOR(2 downto 0);
D : out STD_LOGIC;
T : out STD_LOGIC;
Sel : out STD_LOGIC_VECTOR(1 downto 0);
Sel_1 : out STD_LOGIC;
Sel_Cout : out STD_LOGIC;
Sel_2 : out STD_LOGIC);
end component;
signal sg_arith: STD_LOGIC_VECTOR(15 downto 0);
signal sg_logic: STD_LOGIC_VECTOR(15 downto 0);
signal sg_shift: STD_LOGIC_VECTOR(15 downto 0);
begin
C0: ArithmeticUnit16bit Port Map(A, B, Opcode, sg_arith);
C1: LogicUnit16Bit port map(A,B,Opcode, sg_logic);
C2: Shift port map(A,B,Mode,Opcode(1), sg_shift);
C3: MUX_4_TO_1 port map(sg_arith, sg_logic, sg_shift, "ZZZZZZZZZZZZZZZZ", Opcode, ALUout);
C4: ALUControler port map(Mode, Opcode(2 downto 0));
end Behavioral;
---------------------
--Test Bench
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ALU_TB is
-- Port ( );
end ALU_TB;
architecture Behavioral of ALU_TB is
component ALU16bit is
Port ( A : in STD_LOGIC_VECTOR(15 downto 0);
B : in STD_LOGIC_VECTOR(15 downto 0);
Opcode : in STD_LOGIC_VECTOR(2 downto 0);
Mode : in STD_LOGIC;
ALUout : out STD_LOGIC_VECTOR(15 downto 0);
Cout : out STD_LOGIC);
end component;
signal A: STD_LOGIC_VECTOR(15 downto 0);
signal B: STD_LOGIC_VECTOR(15 downto 0);
signal Opcode: STD_LOGIC_VECTOR(2 downto 0);
signal Mode: STD_LOGIC;
signal ALUout: STD_LOGIC_VECTOR(15 downto 0);
signal Cout: STD_LOGIC;
begin
uut: ALU16bit port map(A=>A, B=>B, Opcode=>Opcode, Mode=>Mode, ALUout=>ALUout, Cout=>Cout);
process
begin
Mode<='0';
Opcode<="000";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="001";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="010";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="011";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="100";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="101";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="110";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='0';
Opcode<="111";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="000";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="001";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="010";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="011";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="100";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="101";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="110";
A<=x"AAAA";
B<=x"BBBB";
wait for 10ns;
Mode<='1';
Opcode<="111";
A<=x"AAAA";
B<=x"BBBB";
end process;
end Behavioral;
Related
I'm writing a program that replys on SIGTERM/SIGINT to terminate. This is a multi-thread program. Basically I have a dedicated thread that is waiting for SIGTERM and SIGINT by calling sigwait and I will notify the main thread upon receving the signals in this thread.
I sent the SIGTERM signal to this program by executing command "killall nameofprocess". However, I found that it will work as expcted only in 10%. Most of times I have to run the "killall" command twice to terminate this program. I'm wondering why the sigwait doesn't capture the SIGTERM the first time. (Same case for SIGINT when I run kill -2)
Is it possible that the signal is received by some other threads?
static std::atomic<bool> shutdown_requested(false);
static std::mutex cv_mutex;
static std::condition_variable cv;
int main()
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
....do something including creating some threads.....
//a dedicated thread that waits for signals
auto signal_handler = [&sigset]() {
int signum = 0;
// wait until a signal is delivered:
sigwait(&sigset, &signum);
shutdown_requested.store(true);
// notify all waiting workers to check their predicate:
cv.notify_all();
return signum;
};
auto signal_handler_async = std::async(std::launch::async, signal_handler);
//wait for cv
while(shutdown_requested.load() == false)
{
std::unique_lock lock(cv_mutex);
cv.wait(lock, [](){return shutdown_requested.load();});
}
..........clean up and exit..............
return 0;
}
I have a bigger project, with a GUI and I want to manage some files in the background. I've implemented a new thread for this task and on runtime, everything works great. But as soon as I quit the application visual-leak-detector finds 3-7 memory leaks.
I separated my threading code and created a new project to check this with a minimal code example, but I'm still not able to fix my issue.
I think it has something to do with the event loop of the main program. Maybe the loop doesn't process the last events to delete my thread class and the thread itself. Because I stop and quit the thread in a destructor. But I'm not sure on this one.
Here is my minimal code:
threadclass.hpp:
#include <QObject>
#include <QDebug>
class ThreadClass : public QObject {
Q_OBJECT
public:
explicit ThreadClass() {}
virtual ~ThreadClass(){
qDebug() << "ThreadClass Destructor";
}
signals:
// emit finished for event loop
void finished();
public slots:
// scan and index all files in lib folder
void scanAll(){
for(long i = 0; i < 10000; i++){
for (long k = 0; k < 1000000; k++);
if(i%500 == 0)
qDebug() << "thread: " << i;
}
}
// finish event loop and terminate
void stop(){
// will be processed after scanall is finished
qDebug() << "STOP SIGNAL --> EMIT FINSIHED";
emit finished();
}
};
threadhandler.hpp:
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
// TODO Check!
// I think I don't have to delete the threads, because delete later
// on finish signal. Maybe I just have to wait, but then how do I
// check, if thread is not finished? Do I need to make a bool var again?
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
emit stopThread();
//my_thread->quit();
my_thread->wait();
//delete my_thread;
}
qDebug() << "ThreadHandler Destructor";
my_thread->dumpObjectInfo();
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
my_thread = new QThread;
ThreadClass *my_threaded_class = new ThreadClass();
my_threaded_class->moveToThread(my_thread);
// start and finish
QObject::connect(my_thread, &QThread::started, my_threaded_class, &ThreadClass::scanAll);
QObject::connect(this, &ThreadHandler::stopThread, my_threaded_class, &ThreadClass::stop);
// finish cascade
// https://stackoverflow.com/a/21597042/6411540
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
QObject::connect(my_threaded_class, &ThreadClass::destroyed, my_thread, &QThread::quit);
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
my_thread->start();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
The main.cpp is crappy but seems to simulate the behavior of my main program well enough:
#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include "threadhandler.hpp"
#include <vld.h>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
ThreadHandler *th = new ThreadHandler();
th->startThread();
// wait (main gui programm)
QTime dieTime= QTime::currentTime().addSecs(5);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
qDebug() << "DELETE TH";
delete th;
qDebug() << "FINISH ALL EVENTS";
QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
qDebug() << "QUIT";
QCoreApplication::quit();
qDebug() << "CLOSE APP";
// pause console
getchar();
// return a.exec();
}
Here is the output from VLD:
WARNING: Visual Leak Detector detected memory leaks!
...
turns out this is very boring and uninteresting
...
Visual Leak Detector detected 3 memory leaks (228 bytes).
Largest number used: 608 bytes.
Total allocations: 608 bytes.
Visual Leak Detector is now exiting.
The program '[8708] SOMinimalExampleThreads.exe' has exited with code 0 (0x0).
Update 1: I added qDebug() << "ThreadClass Destructor"; to the destructor of the ThreadClass and my new output looks like this:
...
thread: 9996
thread: 9997
thread: 9998
thread: 9999
ThreadHandler Destructor
FINISH ALL EVENTS
CLOSE APP
Now it is clear that the destructor of my threaded class is never called and therefore lost in the void. But then why is this not working?
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
Update 2: I found one problem in ThreadHandler:
emit stopThread();
my_thread->quit(); // <-- stops the event loop and therefore no deletelater
my_thread->wait();
I removed my_thread->quit() and now the destructor of ThreadClass is called, but my_thread->wait() never finishes.
Problem description:
When the destructor of ThreadHandler emits stopThread from the main thread, Qt invokes the connected slot (&ThreadClass::stop) by posting an event into the worker thread's event loop (aka, a queued connection). This means that the event loop of the worker's needs to be ready for receiving new events when this signal is emitted (since you are relying on it to perform proper clean-up). However, as you've already spotted, the call to thread->quit() might cause the event loop to quit earlier than desired (before the worker thread makes its way to call ThreadClass::stop, and hence the signal ThreadClass::finished is not emitted). You might want to examine the output of this minimal example that reproduces the behavior I am talking about:
#include <QtCore>
/// lives in a background thread, has a slot that receives an integer on which
/// some work needs to be done
struct WorkerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SLOT void doWork(int x) {
// heavy work in background thread
QThread::msleep(100);
qDebug() << "working with " << x << " ...";
}
};
/// lives in the main thread, has a signal that should be connected to the
/// worker's doWork slot; to offload some work to the background thread
struct ControllerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SIGNAL void sendWork(int x);
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread thread;
WorkerObject workerObj;
workerObj.moveToThread(&thread);
// quit application when worker thread finishes
QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);
thread.start();
ControllerObject controllerObj;
QObject::connect(&controllerObj, &ControllerObject::sendWork, &workerObj,
&WorkerObject::doWork);
for (int i = 0; i < 100; i++) {
QThread::msleep(1);
// call thread.quit() when i is equal to 10
if (i == 10) {
thread.quit();
}
controllerObj.sendWork(i);
}
return a.exec();
}
#include "main.moc"
On my machine, Here is a possible output:
working with 0 ...
working with 1 ...
working with 2 ...
working with 3 ...
Notice that, despite the fact that thread.quit() is called on the tenth iteration from the main thread, the worker thread might not process all messages received before the exit call (and we get the value 3 as the last value processed by the worker).*
Solution:
Actually, Qt provides a canonical to way to quit a worker thread and perform necessary clean-up, since the signal QThread::finished is handled in a special way:
When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
This means that you can use thread->quit() (the same way you were doing), but you just need to add:
connect(my_thread, &QThread::finished, my_threaded_class, &ThreadClass::stop);
to your startThread and remove the unnecessary emit stopThread(); from the destructor.
* I couldn't find any page in the documentation that explains this behavior in detail, so I provided this minimal example to explain what I am talking about.
I found out that the my_thread->wait() function, blocks the event loop and therefore the quit and deleteLater cascade is never finished. I fixed this with another method of waiting for the finished thread:
removed
Here is the newly implemented solution from Mike. It was pretty easy to implement, I only had to change the connection to my_threaded_class::stop in the threadhandler class.
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
my_thread->quit();
my_thread->wait();
}
qDebug() << "ThreadHandler Destructor";
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
my_thread = new QThread;
ThreadClass *my_threaded_class = new ThreadClass();
my_threaded_class->moveToThread(my_thread);
// start and finish
QObject::connect(my_thread, &QThread::started, my_threaded_class, &ThreadClass::scanAll);
// https://stackoverflow.com/questions/53468408
QObject::connect(my_thread, &QThread::finished, my_threaded_class, &ThreadClass::stop);
// finish cascade
// https://stackoverflow.com/a/21597042/6411540
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
QObject::connect(my_threaded_class, &ThreadClass::destroyed, my_thread, &QThread::quit);
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
my_thread->start();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
I am setting up communication via USART2 Asynchronous to receive my data. Configuration for receive the data is 9600/7bit/1-bit stop/Parity Even/Mode Rx/Tx. The implementation works fine when no parity is implemented. But the specification dictates that even parity should be supported.
If added the parity, I received any value.I do not understand where is the problem.
My configuration is with STMCubeMx for STM32L031K6 nucleo.
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_7B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT|UART_ADVFEATURE_DMADISABLEONERROR_INIT;
huart2.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
huart2.AdvancedInit.DMADisableonRxError = UART_ADVFEATURE_DMA_DISABLEONRXERROR;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(uartHandle->Instance==USART2)
{
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
/**USART2 GPIO Configuration
PA9 ------> USART2_TX
PA10 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART2)
{
/* Peripheral clock disable */
__HAL_RCC_USART2_CLK_DISABLE();
/**USART2 GPIO Configuration
PA9 ------> USART2_TX
PA10 ------> USART2_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* Peripheral interrupt Deinit*/
HAL_NVIC_DisableIRQ(USART2_IRQn);
}
}
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
/*Configure GPIO pin : PB3 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/*********************** interruption **********************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2) //current UART
{
Receive();
HAL_UART_Receive_IT(&huart2, Rx_data, 1);
}
}
/******************** Main ******************************/
int main(void)
{
HW_Init();
HAL_UART_Receive_IT(&huart2, Rx_data, 1);
while (1)
{
}
}
When using parity on STM32 series, you need to increase the UART_WORDLENGTH_7B to UART_WORDLENGTH_8B (or UART_WORDLENGTH_9B if you have 8 bits of data).
I just experienced the same problem myself recently. The HAL API should been better at this point...
Scenario
Lets say, I have a procedure called parallelRun. It would take a list of workers, each having a getWorkAmount():int, a run() method, a finished() signal and a cancel() slot:
void parallelRun( std::vector< Worker* > workers );
Its implementation should:
1. Open a QPogressDialog:
unsigned int totalWorkAmount = 0;
for( auto it = workers.begin(); it != workers.end(); ++it )
{
totalWorkAmount += ( **it ).getWorkAmount();
}
LoadUI ui( 0, totalWorkAmount, this );
with
class LoadUI : public QObject
{
Q_OBJECT
public:
LoadUI( int min, int max, QWidget* modalParent )
: totalProgres( 0 )
, progressDlg( "Working", "Abort", min, max, modalParent )
{
connect( &progressDlg, SIGNAL( canceled() ), this, SLOT( cancel() ) );
progressDlg.setWindowModality( Qt::WindowModal );
progressDlg.show();
}
bool wasCanceled() const
{
return progressDlg.wasCanceled();
}
public slots:
void progress( int amount )
{
totalProgres += amount;
progressDlg.setValue( totalProgres );
progressDlg.update();
QApplication::processEvents();
}
signals:
void canceled();
private slots:
void cancel()
{
emit canceled();
}
private:
int totalProgres;
QProgressDialog progressDlg;
}
2. Create one thread for each worker
std::vector< std::unique_ptr< QThread > > threads;
for( auto it = workers.begin(); it != workers.end(); ++it )
{
std::unique_ptr< QThread > thread( new QThread() );
Worker* const worker = *it;
worker->moveToThread( thread.get() );
QObject::connect( worker, SIGNAL( finished() ), thread.get(), SLOT( quit() ) );
QObject::connect( &ui, SIGNAL( canceled() ), worker, SLOT( cancel() ) );
QObject::connect( *it, SIGNAL( progressed( int ) ), &ui, SLOT( progress( int ) ) );
thread->start( priority );
threads.push_back( std::move( thread ) );
}
3. Run them simultaneously
for( auto it = workers.begin(); it != workers.end(); ++it )
{
QMetaObject::invokeMethod( *it, "run", Qt::QueuedConnection );
}
load() is run when the user clicks an UI-button.
Problem
How am I supposed to extend this code, if I want to make parallelRun block until all workers are finished, without freezing the QProgressDialog?
Deliberations
Using a barrier
I tried adding the following code at the end of the parallelRun routine:
QApplication::processEvents();
for( auto it = threads.begin(); it != threads.end(); ++it )
{
( **it ).wait();
}
The impact of this few lines of extra-code is, that LoadUI::progress is never entered, since the GUI-thread is asleep and therefore it's event loop isn't processed: In Qt, signals are delivered to slots by posting them to the event loop of the thread, associated to the object the slot belongs to. This is why the progressed signal of a worker is never delivered.
I think, the appropriate solution would be to run QApplication::processEvents() within the GUI-thread anytime a progressed signal is emitted by a worker. On the other hand, I guess this cannot be done, since the GUI-thread is asleep.
Another possible solution
Another possibility would be to use an active waiting-like solution:
for( auto it = threads.begin(); it != threads.end(); ++it )
{
while( ( **it ).isRunning() )
{
QApplication::processEvents();
}
}
for( auto it = threads.begin(); it != threads.end(); ++it )
{
( **it ).wait();
}
This also requires adding the following line of code right after thread->start( priority );:
while( !thread->isRunning() );
I don't think that this is a nice solution, but at least it works. How can this be done without the drawbacks of active waiting?
Thanks in advance!
You could use the threads' finished() signals to wait for them all to finish in the main GUI loop instead of using QApplication::processEvents. The progress dialog modality will ensure that only that dialog window is active until it is explicitly closed.
class WorkerManager : public QObject {
Q_OBJECT
private:
// to be able to access the threads and ui, they are defined as a members
std::vector<std::unique_ptr<QThread> > threads;
LoadUI *ui;
int finishedThreadCount;
public:
WorkerManager()
: finishedThreadCount(0)
{
// Open the QProgressDialog
...
// Create and start the threads
...
// Connect the finished() signal of each thread
// to the slot onThreadFinished
for( auto it = threads.begin(); it != threads.end(); ++it ) {
QObject::connect(
it->get(), SIGNAL(finished()),
this, SLOT(onThreadFinished()) );
}
}
private slots:
void onThreadFinished() {
++finishedThreadCount;
if(finishedThreadCount == threads.size())
{
// clean up the threads if necessary
// close the dialog
// and eventually destroy the object this itself
}
}
};
Or you can run a nested QEventLoop to wait for the threads to finish synchronously while still keeping the GUI responsive:
// Open the QProgressDialog
...
// Create and start the threads
...
// Create and run a local event loop,
// which will be interrupted each time a thread finishes
QEventLoop loop;
for( auto it = threads.begin(); it != threads.end(); ++it )
{
QObject::connect(
it->get(), SIGNAL(finished()),
&loop, SLOT(quit()) );
}
for(int i = 0, threadCount = threads.size(); i < threadCount; ++i)
loop.exec();
If the progress reach the maximum only when the work is completely done, you can use progressDlg->exec() instead of a QEventLoop which will block until the maximum is reached or until the user clicks on the "Cancel" button.
Instead of building your own. Maybe QThreadPool is what you are looking for?
QThreadPool has a function for waiting for all workers.
Qt :: WindowFlags flags = 0;
// Makes the Pomodoro stay on the top of all windows.
flags |= Qt :: WindowStaysOnTopHint;
// Removes minimize, maximize, and close buttons.
flags |= Qt :: WindowTitleHint | Qt :: CustomizeWindowHint;
window->setWindowFlags (flags);
window->setWindowTitle ("Failing to plan is planning to fail");
This removes minimize, maximize, and close buttons. The default menu on the left is still there. How to get rid of that?
I want the title bar to be there, but just want the menu to be removed.
Default menu contains: Minimize, Maximize, Move etc options.
EDIT 1:
timer.cpp
#include <QApplication>
#include <QMainWindow>
#include "timer.h"
#include <QPushButton>
#include <QListWidget>
#include <QtGui>
#include <QTreeWidget>
int main(int argc, char *argv[])
{
QApplication app (argc, argv);
// The window on which we will place the timer.
QMainWindow *window = new QMainWindow();
QWidget *centralWidget = new QWidget (window);
/* Button widget */
// Displays a button on the main window.
QPushButton *startButton = new QPushButton("Start", window);
// Setting the size of the button widget.
startButton->setFixedSize (245, 25);
/* Text box */
// Displays a time interval list on the main window.
QListWidget *timeIntervalList = new QListWidget (window);
timeIntervalList->setFixedSize (30, 145);
QStringList timeIntervals;
timeIntervals << "1" << "20" << "30" << "40";
timeIntervalList->addItems (timeIntervals);
/* LCD widget */
// Start Counting down from 25 minutes
lcdDisplay *objLcdDisplay = new lcdDisplay (centralWidget);
// Setting the size of the LCD widget.
objLcdDisplay->setFixedSize (245, 140);
// The clicked time interval should be returned from the list to the timer.
QObject :: connect (timeIntervalList, SIGNAL (itemClicked (QListWidgetItem *)), objLcdDisplay, SLOT (receiveTimeInterval (QListWidgetItem *)));
// The timer should start and emit signals when the start button is clicked.
QObject :: connect (startButton, SIGNAL (clicked ()), objLcdDisplay, SLOT (setTimerConnect ()));
*************************************************************************
Qt :: WindowFlags flags = 0;
// Makes the Pomodoro stay on the top of all windows.
flags |= Qt :: Window | Qt :: WindowStaysOnTopHint;
// Removes minimize, maximize, and close buttons.
flags |= Qt :: WindowTitleHint | Qt :: CustomizeWindowHint;
window->setWindowFlags (flags);
*************************************************************************
window->setWindowTitle ("Failing to plan is planning to fail");
QGridLayout *layout = new QGridLayout();
centralWidget->setLayout(layout);
//Add Items to QGridLayout Here
//Row and Column counts are set Automatically
layout->addWidget (objLcdDisplay, 0, 1);
layout->addWidget (startButton, 1, 1);
layout->addWidget (timeIntervalList, 0, 0);
window->setCentralWidget (centralWidget);
window->show();
return app.exec();
}
Timer.h
#ifndef LCDNUMBER_H
#define LCDNUMBER_H
#include <QLCDNumber>
#include <QTimer>
#include <QTime>
#include <QListWidget>
#include <QMessageBox>
#include <iostream>
class lcdDisplay : public QLCDNumber
{
Q_OBJECT
public:
// The QTimer class provides repetitive and single-shot timers.
QTimer* objTimer;
// The QTime class provides clock time functions.
QTime* objTime;
public:
lcdDisplay (QWidget *parentWidget)
{
objTimer = new QTimer ();
// Setting our own time with the specified hours, minutes, and seconds.
objTime = new QTime (0, 0, 0);
setParent (parentWidget);
};
~ lcdDisplay () {};
public slots:
// This slot is called after the timer timeouts (1 second).
void setDisplay ()
{
// TODO
objTime->setHMS (0, objTime->addSecs (-1).minute (), objTime->addSecs (-1).second ());
display (objTime->toString ());
if ((objTime->minute () == 0) && (objTime->second () == 0))
{
objTimer->stop ();
QMessageBox msgBox;
msgBox.setWindowTitle ("Pomodoro");
msgBox.setText ("Time's up.");
msgBox.setWindowModality(Qt::ApplicationModal);
msgBox.exec();
}
};
void receiveTimeInterval (QListWidgetItem *item)
{
QString h = item->text();
objTime->setHMS (0, h.toUInt(), 0);
}
void setTimerConnect ()
{
// connect (objectA, signalAFromObjectA, objectB, slotAFromObjectB)
// timeout (): This signal is emitted when the timer times out. The time out period can be specified with `start (int milliseconds)` function.
QObject :: connect (objTimer, SIGNAL (timeout ()), this, SLOT (setDisplay ()));
// 1 second has 1000 milliseconds.
// start (int milliseconds): Starts the timer with a timeout interval of specified milliseconds. this means that after 1 second the timer will emit a signal. TODO placement
objTimer->start (1000);
}
};
#endif
This is working for me:
Qt::Window | Qt::WindowTitleHint | Qt::WindowStaysOnTopHint | Qt::CustomizeWindowHint
Sometimes you have to specify these in the constructor of the window for them to take effect. If you assign them later (setWindowFlags), some of the settings may not apply.
I'm currently at work without an Qt environment, so I could not test it. Would you please try this?
Qt::WindowFlags flags = 0;
// Makes the Pomodoro stay on the top of all windows.
flags |= Qt :: WindowStaysOnTopHint;
// Removes minimize, maximize, and close buttons.
flags |= Qt :: WindowTitleHint | Qt :: CustomizeWindowHint;
window->setWindowFlags (flags & ~Qt::WindowSystemMenuHint);
window->setWindowTitle ("Failing to plan is planning to fail");
Try to start by setting Qt::Dialog
setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowStaysOnTopHint);