File: thread.cpp

package info (click to toggle)
threadweaver 5.54.0-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 2,252 kB
  • sloc: cpp: 7,105; python: 33; sh: 14; makefile: 9
file content (134 lines) | stat: -rw-r--r-- 3,734 bytes parent folder | download
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* -*- C++ -*-

   This file is part of ThreadWeaver. It implements the Thread class.

   $ Author: Mirko Boehm $
   $ Copyright: (C) 2004-2013 Mirko Boehm $
   $ Contact: mirko@kde.org
         http://www.kde.org
         http://creative-destruction.me $

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

   $Id: Thread.cpp 25 2005-08-14 12:41:38Z mirko $
*/

#include "thread.h"

#include <QMutex>
#include <QDebug>
#include <QPointer>
#include <QCoreApplication>

#include "threadweaver.h"
#include "weaver.h"
#include "job.h"
#include "debuggingaids.h"
#include "exception.h"

using namespace ThreadWeaver;

class Q_DECL_HIDDEN Thread::Private
{
public:
    explicit Private(Weaver *theParent)
        : parent(theParent)
        , id(makeId())
        , job(nullptr)
    {
        Q_ASSERT(parent);
    }

    Weaver *parent;
    const unsigned int id;
    JobPointer job;
    QMutex mutex;

    static unsigned int makeId()
    {
        static QAtomicInt s_id(1);
        return s_id.fetchAndAddRelease(1);
    }
};

Thread::Thread(Weaver *parent)
    : QThread() // no parent, because the QObject hierarchy of this thread
    // does not have a parent (see QObject::pushToThread)
    , d(new Private(parent))
 {
    const QString queueName = parent->objectName().isEmpty()
            ? QString::fromLatin1("Queue(0x%1)").arg(quintptr(parent), 0, 16, QChar::fromLatin1('0'))
            : parent->objectName();
    setObjectName(QString::fromLatin1("%1[%2]").arg(queueName).arg(QString::number(id()), 2, QChar::fromLatin1('0')));
}

Thread::~Thread()
{
    delete d;
}

unsigned int Thread::id() const
{
    return d->id; //id is const
}

void Thread::run()
{
    Q_ASSERT(d->parent);
    Q_ASSERT(QCoreApplication::instance() != nullptr);
    d->parent->threadEnteredRun(this);

    emit started(this);
    TWDEBUG(3, "Thread::run [%u]: running.\n", id());

    bool wasBusy = false;
    while (true) {
        TWDEBUG(3, "Thread::run [%u]: trying to execute the next job.\n", id());

        try {
            // the assignment is intentional: newJob needs to go out of scope at the end of the if statement
            if (JobPointer newJob = d->parent->applyForWork(this, wasBusy)) {
                QMutexLocker l(&d->mutex); Q_UNUSED(l);
                d->job = newJob;
            } else {
                break;
            }
        } catch (AbortThread&) {
            break;
        }

        wasBusy = true;
        d->job->execute(d->job, this);
        JobPointer oldJob;
        {   // When finally destroying the last reference to d->job, do not hold the mutex.
            // It may trigger destruction of the job, which can execute arbitrary code.
            QMutexLocker l(&d->mutex); Q_UNUSED(l);
            oldJob = d->job;
            d->job.clear();
        }
        oldJob.clear();
    }
    TWDEBUG(3, "Thread::run [%u]: exiting.\n", id());
}

void Thread::requestAbort()
{
    QMutexLocker l(&d->mutex); Q_UNUSED(l);
    if (d->job) {
        d->job->requestAbort();
    }
}