Dec 16, 2011 at 4:52pm UTC
Hi,
my goal is to implement two threads. One running a vector of numbers upwards, the other one running the vector downwards. Both should set numbers in this vector to zero. So I use a global variable vector which should be mutexed.
When I run the following code just the second threads runs. When I slightly modify the data structure of the delivered arguments to the threads to a static object (i.e. setting thread data as a static array), the code works (see second code snippet). Why is that so?
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
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <pthread.h>
using namespace std;
const unsigned long MAX_NUMBER = 1000000;
vector<bool > numbers(MAX_NUMBER+1);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
unsigned long l1,l2;
// thread specific arguments
struct thread_data
{
unsigned int thread_id;
unsigned long n; // data to sieve
bool bw; // backward or forward search
};
void init_numbers(vector <bool > * numbers);
void *prime_sieve(void *arg);
void init_numbers(vector <bool > * numbers)
{
unsigned long i;
(*numbers)[2]=true ;
for (i=3;i<=MAX_NUMBER;i+=2){(*numbers)[i]=true ;}
}
void *prime_sieve(void *arg)
{
struct thread_data *my_data;
my_data = (struct thread_data *)arg;
unsigned long i;
unsigned long c;
unsigned long pos_move;
if (!(my_data->bw))
{
while (l1 <= l2)
{
if (numbers[l1] != false )
{
c = l1*l1;
pos_move = (l1 << 1);
while (c <= my_data->n)
{
pthread_mutex_lock(&mutex1);
numbers[c]=false ;
pthread_mutex_unlock(&mutex1);
c += pos_move;
}
}
pthread_mutex_lock(&mutex1);
l1++;
cout << "l1 " << l1 << endl;
pthread_mutex_unlock(&mutex1);
}
}
else
{
while (l2 >= l1)
{
if (numbers[l2] != false )
{
c = l2*l2;
pos_move = (l2 << 1);
while (c <= my_data->n)
{
pthread_mutex_lock(&mutex1);
numbers[c]=false ;
pthread_mutex_unlock(&mutex1);
c += pos_move;
}
}
pthread_mutex_lock(&mutex1);
l2--;
cout << "l2 " << l2 << endl;
pthread_mutex_unlock(&mutex1);
}
}
pthread_exit(NULL);
}
unsigned long get_primes(vector <bool > numbers, unsigned long n)
{
unsigned long primes=0;
for (unsigned int i=0;i<=n;i++)
{
primes+=numbers[i];
}
return primes;
}
int main(int argc, char *argv[])
{
pthread_t threads[2];
int rc;
unsigned long n = MAX_NUMBER;
init_numbers(&numbers);
l1 = 2;
l2 = (int )(sqrt(n))+1;
struct thread_data my_data;
my_data.thread_id = 0;
my_data.n = MAX_NUMBER;
my_data.bw = false ;
rc = pthread_create(&threads[0], NULL, prime_sieve, (void *) &my_data);
struct thread_data my_data2;
my_data2.thread_id = 1;
my_data2.n = MAX_NUMBER;
my_data.bw = true ;
rc = pthread_create(&threads[1], NULL, prime_sieve, (void *) &my_data2);
void * retval;
pthread_join(threads[0], &retval);
pthread_join(threads[1], &retval);
cout << get_primes(numbers, n) << endl;
}
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
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <pthread.h>
using namespace std;
const unsigned long MAX_NUMBER = 1000000;
vector<bool > numbers(MAX_NUMBER+1);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
unsigned long l1,l2;
// thread specific arguments
struct thread_data
{
unsigned int thread_id;
unsigned long n; // data to sieve
bool bw; // backward or forward search
};
struct thread_data thread_data_array[2];
void init_numbers(vector <bool > * numbers);
void *prime_sieve(void *arg);
void init_numbers(vector <bool > * numbers)
{
unsigned long i;
(*numbers)[2]=true ;
for (i=3;i<=MAX_NUMBER;i+=2){(*numbers)[i]=true ;}
}
void *prime_sieve(void *arg)
{
struct thread_data *my_data;
my_data = (struct thread_data *)arg;
unsigned long i;
unsigned long c;
unsigned long pos_move;
if (!(my_data->bw))
{
while (l1 <= l2)
{
if (numbers[l1] != false )
{
c = l1*l1;
pos_move = (l1 << 1);
while (c <= my_data->n)
{
pthread_mutex_lock(&mutex1);
numbers[c]=false ;
pthread_mutex_unlock(&mutex1);
c += pos_move;
}
}
pthread_mutex_lock(&mutex1);
l1++;
cout << "l1 " << l1 << endl;
pthread_mutex_unlock(&mutex1);
}
}
else
{
while (l2 >= l1)
{
if (numbers[l2] != false )
{
c = l2*l2;
pos_move = (l2 << 1);
while (c <= my_data->n)
{
pthread_mutex_lock(&mutex1);
numbers[c]=false ;
pthread_mutex_unlock(&mutex1);
c += pos_move;
}
}
pthread_mutex_lock(&mutex1);
l2--;
cout << "l2 " << l2 << endl;
pthread_mutex_unlock(&mutex1);
}
}
pthread_exit(NULL);
}
unsigned long get_primes(vector <bool > numbers, unsigned long n)
{
unsigned long primes=0;
for (unsigned int i=0;i<=n;i++)
{
primes+=numbers[i];
}
return primes;
}
int main(int argc, char *argv[])
{
pthread_t threads[2];
int rc;
unsigned long n = MAX_NUMBER;
init_numbers(&numbers);
l1 = 2;
l2 = (int )(sqrt(n))+1;
thread_data_array[0].thread_id = 0;
thread_data_array[0].n = MAX_NUMBER;
thread_data_array[0].bw = false ;
rc = pthread_create(&threads[0], NULL, prime_sieve, (void *) &thread_data_arr\
ay[0]);
thread_data_array[1].thread_id = 1;
thread_data_array[1].n = MAX_NUMBER;
thread_data_array[1].bw = true ;
rc = pthread_create(&threads[1], NULL, prime_sieve, (void *) &thread_data_arr\
ay[1]);
void * retval;
pthread_join(threads[0], &retval);
pthread_join(threads[1], &retval);
cout << get_primes(numbers, n) << endl;
}
Last edited on Dec 16, 2011 at 4:59pm UTC
Dec 16, 2011 at 9:59pm UTC
Both threads run in both cases (place an output statement at the beginning of prime_sieve(), to see for yourself), but in the first case, the first thread was able to run to completion before the second thread ever got scheduled to run. In the second case, the first thread took a little longer to execute, and the second thread started working before the first one finished.
In addition, your threads are not synchronized on l1 or l2 or on the elements of numbers - the mutexes present do nothing useful, except for synchronizing the two output statements.
Last edited on Dec 16, 2011 at 10:01pm UTC