-
Notifications
You must be signed in to change notification settings - Fork 3
/
ptest.c
153 lines (138 loc) · 4.38 KB
/
ptest.c
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) 2015 Pierre Guillot.
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*/
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define BUFSIZE 128
#define NCONSUMER 5
#define NLOOPS 10
static void verbose_printf(char const* buf)
{
#ifdef VERBOSE_TEST
printf("%s", buf);
#endif
}
//! @brief A sample data structure for threads to use.
//! @details The structure is passed by void pointer to the thread so it can be any data type.
//! The structure owns a mutex to synchronize the access to the data.
typedef struct _data
{
pthread_mutex_t mutex; //!< The mutex.
pthread_cond_t condwrite; //!< The condition.
pthread_cond_t condread; //!< The condition.
char occupied; //!< The state.
char buffer[BUFSIZE];//!< The buffer.
}t_data;
//! @brief The function that writes in the buffer.
//! @details The function uses the mutex to ensure the synchronization of the access to the
//! data and uses condition to to ensure that all the consumer has read the data.
static void func_producer(t_data* t)
{
size_t i;
//! Locks the access to the data
pthread_mutex_lock(&t->mutex);
//! Wait the condition to write the data
verbose_printf("func_producer wait...\n");
while(t->occupied)
{
pthread_cond_wait(&t->condwrite, &t->mutex);
}
assert(!t->occupied);
verbose_printf("func_producer run...\n");
//! Write to the buffer.
for(i = 0; i < BUFSIZE; i++)
{
t->buffer[i] = (char)i;
}
t->occupied = NCONSUMER;
//! Signal that the buffer can be read
verbose_printf("func_producer signal\n");
pthread_cond_signal(&t->condread);
//! Unlocks the access to the data
pthread_mutex_unlock(&t->mutex);
}
//! @brief The function that reads from the buffer.
//! @details The function uses the mutex to ensure the synchronization of the access to the
//! data and uses condition to to ensure that all the producer has write the data.
static void func_consumer(t_data* t)
{
size_t i;
//! Locks the access to the data
pthread_mutex_lock(&t->mutex);
//! Wait the condition to write the data
verbose_printf("func_consumer wait...\n");
while(!t->occupied)
{
pthread_cond_wait(&t->condread, &t->mutex);
}
assert(t->occupied);
verbose_printf("func_consumer run...\n");
//! Write to the buffer.
for(i = 0; i < BUFSIZE; i++)
{
assert(t->buffer[i] == i);
}
t->occupied--;
verbose_printf("func_consumer signal\n");
if(t->occupied)
{
//! Signal that the buffer can be read by another thread
pthread_cond_signal(&t->condread);
}
else
{
//! Signal that the buffer can be write
pthread_cond_signal(&t->condwrite);
}
//! Unlocks the access to the data
pthread_mutex_unlock(&t->mutex);
}
int main(int argc, char** argv)
{
size_t i, j;
//! The data structure that will be accessed by the threads
t_data data;
//! The set of consumer threads
pthread_t producer;
pthread_t consumers[NCONSUMER];
//! Note that the data is free to be filled
data.occupied = 0;
printf("test thread... ");
//! Initializes the mutex of the data structure
pthread_mutex_init(&data.mutex, NULL);
//! Initializes the conditions of the data structure
pthread_cond_init(&data.condread, NULL);
pthread_cond_init(&data.condwrite, NULL);
for(j = 0; j < NLOOPS; j++)
{
//! Fill the data's buffer with 0
for(i = 0; i < BUFSIZE; i++)
{
data.buffer[i] = 0;
}
//! Detaches all the threads
for(i = 0; i < NCONSUMER; i++)
{
pthread_create(consumers+i, 0, (void *)func_consumer, &data);
}
pthread_create(&producer, 0, (void *)func_producer, &data);
//! Joins all the threads
pthread_join(producer, NULL);
for(i = 0; i < NCONSUMER; i++)
{
pthread_join(consumers[i], NULL);
}
}
//! Destroy the conditions of the data structure
pthread_cond_destroy(&data.condread);
pthread_cond_destroy(&data.condwrite);
//! Destroy the mutex of the data structure
pthread_mutex_destroy(&data.mutex);
printf("ok\n");
return 0;
}