-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathscm-queue.hpp
151 lines (120 loc) · 3.73 KB
/
scm-queue.hpp
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright (C) 2011-2012 Robert Kooima
//
// LIBSCM is free software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITH-
// OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
#ifndef SCM_QUEUE_HPP
#define SCM_QUEUE_HPP
#include <SDL.h>
#include <SDL_thread.h>
#include <set>
//------------------------------------------------------------------------------
/// An scm_queue implements a templated producer-consumer priority queue.
///
/// Priority is given by the partial ordering on the templated type.
///
/// A "needs" queue is used by the render thread to delegate work to a set of
/// loader threads. A "loads" queue is used by the loader threads to return
/// their results to the render thread. In all cases, the loader threads perform
/// blocking operations while the render thread uses non-blocking operations to
/// ensure that frames are not dropped due to data latency.
///
/// @see scm_file
/// @see scm_cache
template <typename T> class scm_queue
{
public:
scm_queue(int n);
~scm_queue();
bool try_insert(T&);
bool try_remove(T&);
void insert(T);
T remove( );
private:
SDL_sem *full_slots;
SDL_sem *free_slots;
SDL_mutex *data_mutex;
std::set<T> S;
};
//------------------------------------------------------------------------------
/// Create a new queue with n slots. Initialize counting semaphores for full
/// slots and empty slots, plus a mutex to protect the data.
template <typename T> scm_queue<T>::scm_queue(int n)
{
full_slots = SDL_CreateSemaphore(0);
free_slots = SDL_CreateSemaphore(n);
data_mutex = SDL_CreateMutex();
}
/// Finalize a queue and release its mutex and semaphores.
template <typename T> scm_queue<T>::~scm_queue()
{
SDL_DestroyMutex (data_mutex);
SDL_DestroySemaphore(free_slots);
SDL_DestroySemaphore(full_slots);
}
//------------------------------------------------------------------------------
/// Non-blocking enqueue for use by the render thread.
template <typename T> bool scm_queue<T>::try_insert(T& d)
{
if (SDL_SemTryWait(free_slots) == 0)
{
SDL_LockMutex(data_mutex);
{
S.insert(d);
}
SDL_UnlockMutex(data_mutex);
SDL_SemPost(full_slots);
return true;
}
return false;
}
/// Non-blocking dequeue for use by the render thread.
template <typename T> bool scm_queue<T>::try_remove(T& d)
{
if (SDL_SemTryWait(full_slots) == 0)
{
SDL_LockMutex(data_mutex);
{
d = *(S.begin());
S.erase(S.begin());
}
SDL_UnlockMutex(data_mutex);
SDL_SemPost(free_slots);
return true;
}
return false;
}
//------------------------------------------------------------------------------
/// Blocking enqueue for use by the loader threads.
template <typename T> void scm_queue<T>::insert(T d)
{
SDL_SemWait(free_slots);
SDL_LockMutex(data_mutex);
{
S.insert(d);
}
SDL_UnlockMutex(data_mutex);
SDL_SemPost(full_slots);
}
/// Blocking dequeue for use by the loader threads.
template <typename T> T scm_queue<T>::remove()
{
T d;
SDL_SemWait(full_slots);
SDL_LockMutex(data_mutex);
{
d = *(S.begin());
S.erase(S.begin());
}
SDL_UnlockMutex(data_mutex);
SDL_SemPost(free_slots);
return d;
}
//------------------------------------------------------------------------------
#endif