My program uses an enum as a semaphore. There are two possible values/states(Because it's a binary semaphore). The program compiles fine. signal() and wait() look logical. Why is program behavior so unpredictable? Even the integer printf is buggy. Here's the code:
#include <stdio.h>
#include <pthread.h>
typedef enum {IN_USE,NOT_IN_USE} binary_semaphore;
binary_semaphore s=NOT_IN_USE;
struct parameters{
int thread_num;
};
void wait(){
while(s==IN_USE);
s=IN_USE;
}
void signal(){
s=NOT_IN_USE;
}
void resource(void *params){
//assuming parameter is a parameters struct.
struct parameters *p=(struct parameters*)params;
wait();
printf("Resource is being used by thread %d\n",(*p).thread_num);
signal();
}
int main(void){
pthread_t threads[4];
struct parameters ps[4]={{1},{2},{3},{4}};
register int counter=0;
while(counter++<4){
pthread_create(&threads[counter],NULL,resource,(void*)&ps[counter]);
}
return 0;
}
What's wrong with my code?
Some of the outputs(Yes, they're different every time):-
(NOTHING)
Resource is being used by thread 32514
Resource is being used by thread 0
Resource is being used by thread 0
Resource is being used by thread 32602
Resource is being used by thread -24547608
Is it a garbage value issue?
What's wrong with my code?
Multiple things, largely discussed in comments already. The most significant one is that your code is rife with data races. That is one of the things that semaphores are often used to protect against, but in this case it is your semaphores themselves that are racy. Undefined behavior results.
Additional issues include
A pthreads thread function must return void *, but yours returns void
You overrun the bounds of your main()'s ps and threads arrays
You do not join your threads before the program exits.
You define functions with the same names as a C standard library function (signal()) and a standard POSIX function (wait()).
Nevertheless, if your C implementation supports the atomics option then you can use that to implement a working semaphore not too different from your original code:
#include <stdio.h>
#include <pthread.h>
#include <stdatomic.h>
// This is used only for defining the enum constants
enum sem_val { NOT_IN_USE, IN_USE };
// It is vital that sem be *atomic*.
// With `stdatomic.h` included, "_Atomic int" could also be spelled "atomic_int".
_Atomic int sem = ATOMIC_VAR_INIT(NOT_IN_USE);
struct parameters{
int thread_num;
};
void my_sem_wait() {
int expected_state = NOT_IN_USE;
// See discussion below
while (!atomic_compare_exchange_strong(&sem, &expected_state, IN_USE)) {
// Reset expected_state
expected_state = NOT_IN_USE;
}
}
void my_sem_signal() {
// This assignment is performed atomically because sem has atomic type
sem = NOT_IN_USE;
}
void *resource(void *params) {
//assuming parameter is a parameters struct.
struct parameters *p = params;
my_sem_wait();
printf("Resource is being used by thread %d\n", p->thread_num);
my_sem_signal();
return NULL;
}
int main(void) {
pthread_t threads[4];
struct parameters ps[4] = {{1},{2},{3},{4}};
for (int counter = 0; counter < 4; counter++) {
pthread_create(&threads[counter], NULL, resource, &ps[counter]);
}
// It is important to join the threads if you care that they run to completion
for (int counter = 0; counter < 4; counter++) {
pthread_join(threads[counter], NULL);
}
return 0;
}
Most of that is pretty straightforward, but the my_sem_wait() function bears a little more explanation. It uses an atomic compare-and-swap to make sure that threads proceed only if they change the value of the semaphore from NOT_IN_USE to IN_USE, with the comparison and conditional assignment being performed as a single atomic unit. Specifically, this ...
atomic_compare_exchange_strong(&sem, &expected_state, IN_USE)
... says "Atomically, compare the value of sem to the value of expected_state and if they compare equal then assign value IN_USE to to sem." The function additionally sets the value of expected_state to the one read from sem if they differ, and returns the result of the equality comparison that was performed (equivalently: returns 1 if the specified value was assigned to sem and 0 if not).
It is essential that the comparison and swap be performed as an atomic unit. Individual atomic reads and writes would ensure that there is no data race, but they would not ensure correct program behavior, because two threads waiting on the semaphore could both see it available at the same time, each before the other had a chance to mark it unavailable. Both would then proceed. The atomic compare and swap prevents one thread reading the value of the semaphore between another's read and update of that value.
Do note, however, that unlike a pthreads mutex or a POSIX semaphore, this semaphore waits busily. That means threads waiting to acquire the semaphore consume CPU while they do, rather than going to sleep as threads waiting on a pthreads mutex do. That may be ok if semaphore access is usually uncontended or if threads never hold it locked very long, but under other circumstances it can make your program much more resource-hungry than it needs to be.
You are encountering race conditions as well as undefined behavior. When you use a regular int as a semaphore in multithreaded applications, there's no guarantee that a process will read a variable's value and modify it before another process is able to read it, which is why you must use a concurrency library designed for your operating system. Furthermore, the function pointer you passed to pthread_create is not the right type, which is undefined behavior.
I replaced your "semaphore" enum with a pointer to pthread_mutex_t which is initialized on the stack of main(), and each thread gets a pointer to it as a member of their struct parameter.
I also changed the definition of void resource(void* params) to void* resource(void *params) as that is a prototype that matches what pthread_create expects as its third parameter.
Your wait() and signal() functions were able to be replaced one-to-one with pthread_mutex_lock() and pthread_mutex_unlock() from pthread.h which you have already included.
#include <stdio.h>
#include <pthread.h>
struct parameters{
int thread_num;
pthread_mutex_t *mutex; //mutex could be global if you prefer
};
void* resource(void *params){ //pthread_create expects a pointer to a function that takes a void* and returns a void*
//assuming parameter is a parameters struct.
struct parameters *p = (struct parameters*)params;
pthread_mutex_lock(p->mutex);
printf("Resource is being used by thread %d\n", p->thread_num);
pthread_mutex_unlock(p->mutex);
return NULL;
}
int main(void){
pthread_t threads[4];
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
struct parameters ps[4]={{1, &mutex},{2, &mutex},{3, &mutex},{4, &mutex}};
for(int counter = 0; counter < 4; ++counter)
pthread_create(&threads[counter], NULL, resource, &ps[counter]);
//Threads should be joined
for(int counter = 0; counter < 4; ++counter)
pthread_join(threads[counter], NULL);
}
This will eliminate the stochasticity that you are experiencing.
Related
Considering the following code:
#define _XOPEN_SOURCE 600
#define _DEFAULT_SOURCE
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define ENTRY_NUM 100
struct value {
pthread_mutex_t mutex;
int i;
};
struct entry {
atomic_uintptr_t val;
};
struct entry entries[ENTRY_NUM];
void* thread1(void *arg)
{
for (int i = 0; i != ENTRY_NUM; ++i) {
struct value *val = (struct value*) atomic_load(&entries[i].val);
if (val == NULL)
continue;
pthread_mutex_lock(&val->mutex);
printf("%d\n", val->i);
pthread_mutex_unlock(&val->mutex);
}
return NULL;
}
void* thread2(void *arg)
{
/*
* Do some costy operations before continuing.
*/
usleep(1);
for (int i = 0; i != ENTRY_NUM; ++i) {
struct value *val = (struct value*) atomic_load(&entries[i].val);
pthread_mutex_lock(&val->mutex);
atomic_store(&entries[i].val, (uintptr_t) NULL);
pthread_mutex_unlock(&val->mutex);
pthread_mutex_destroy(&val->mutex);
free(val);
}
return NULL;
}
int main() {
for (int i = 0; i != ENTRY_NUM; ++i) {
struct value *val = malloc(sizeof(struct value));
pthread_mutex_init(&val->mutex, NULL);
val->i = i;
atomic_store(&entries[i].val, (uintptr_t) val);
}
pthread_t ids[2];
pthread_create(&ids[0], NULL, thread1, NULL);
pthread_create(&ids[1], NULL, thread2, NULL);
pthread_join(ids[0], NULL);
pthread_join(ids[1], NULL);
return 0;
}
Suppose in function thread1, entries[i].val is loaded, then the scheduler schedule the process to sleep.
Then thread2 awakes from usleep, since ((struct val*) entries[0].val)->mutex aren't locked, thread2 locks it, stores NULL to entries[0].val and free the original of entries[0].val.
Now, is that a race condition? If so, how to avoid this without locking entries or entries[0]?
You are correct my friend, there is indeed a race condition in such code.
Let me open by overall and saying that thread is prawn to race conditions by definition and this is also correct for any other library implemented thread which is unacknowledged by your compiler ahead of compilation time.
Regarding your specific example, yes as you've explained yourself since we can not assume when does your scheduler go into action, thread1 could atomic load your entries, context switch to thread2, which will then free these entries before thread1 gets processor time again. How do you prevent or avoid such race conditions? avoid accessing them without locking them, even though atomic load is an "atomic read" you are logically allowing other threads to access these entries. the entire code scope of both thread1 and thread2 should be protected with a mutex. despite using atomic_load, you are just guaranteeing that at that atomic time, no other accesses to that entry will be made, but during the time between the atomic_load and your first calling to pthread_mutex_lock context switches can indeed occur! as you've mentioned yourself, this is both bad practice and logically wrong. - hence as I've already stated, you should protect the entire scope with pthread_mutex_lock
In general, as I've stated in the beginning of this, considering that your compiler is unaware to the concept of threads during compilation times, it is very sensitive to race conditions that you may not even be aware of, - e.g.: when accessing different areas of some shared memory, the compiler does not take into consideration that other threads may exist and accesses some memory as it desires, and may affect different areas of memories during, even though logically the code itself doesn't, and the "correctness" of the code is valid.
there was some paper published on this called
Threads Cannot be Implemented as a Library by Hans-J Boehm I highly suggest you read it, I promise it will increase your understanding of race conditions and threads using pthread at general!
I'm doing a C application that reads and parses data from a set of sensors and, according to the readings of the senors, it turns on or off actuators.
For my application I will be using two threads, one to read and parse the data from the sensors and another one to act on the actuators. Obviously we may face the problem of one thread reading data from a certain variable while another one is trying to write on it. This is a sample code.
#include <pthread.h>
int sensor_values;
void* reads_from_sensor(){
//writes on sensor_values, while(1) loop
}
void* turns_on_or_off(){
//reads from sensor_values, while(1) loop
}
int main(){
pthread_t threads[2];
pthread_create(&threads[1],NULL,reads_from_sensor,NULL);
pthread_create(&threads[2],NULL,turns_on_or_off,NULL);
//code continues after
}
My question is how I can solve this issue, of a certain thread writing on a certain global variable while other thread is trying to read from it, at the same time. Thanks in advance.
OP wrote in the comments
The project is still in an alpha stage. I'll make sure I optimize it once it is done. #Pablo, the shared variable is sensor_values. reads_from_sensors write on it and turns_on_or_off reads from it.
...
sensor_value would be a float as it stores a value measured by a certain sensor. That value can either be voltage, temperature or humidity
In that case I'd use conditional variables using pthread_cond_wait and
pthread_cond_signal. With these functions you can synchronize threads
with each other.
The idea is that both threads get a pointer to a mutx, the condition variable
and the shared resource, whether you declared them a global or you pass them as
thread arguments, doesn't change the idea. In the code below I'm passing all
of these as thread arguments, because I don't like global variables.
The reading thread would lock the mutex and when it reads a new value of the
sensor, it writes the new value in the shared resource. Then it call
pthread_cond_signal to send a signal to the turning thread that a new value
arrived and that it can read from it.
The turning thread would also lock the mutex and execute pthread_cond_wait to
wait on the signal. The locking must be done in that way, because
pthread_cond_wait will release the lock and make the thread block until the
signal is sent:
man pthread_cond_wait
DESCRIPTION
The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. The application shall ensure that
these functions are called with mutex locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust
mutexes) or undefined behavior (for other mutexes) results.
These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means
atomically with respect to access by another thread to the mutex and then the condition variable. That is, if another thread is
able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or
pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.
Example:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct thdata {
pthread_mutex_t *mutex;
pthread_cond_t *cond;
int *run;
float *sensor_value; // the shared resource
};
void *reads_from_sensors(void *tdata)
{
struct thdata *data = tdata;
int i = 0;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
// read from sensor
*data->sensor_value = (rand() % 2000 - 1000) / 10.0;
// just for testing, send a singnal only every
// 3 reads
if((++i % 3) == 0)
{
printf("read: value == %f, sending signal\n", *data->sensor_value);
pthread_cond_signal(data->cond);
}
pthread_mutex_unlock(data->mutex);
sleep(1);
}
// sending signal so that other thread can
// exit
pthread_mutex_lock(data->mutex);
pthread_cond_signal(data->cond);
pthread_mutex_unlock(data->mutex);
puts("read: bye");
pthread_exit(NULL);
}
void *turns_on_or_off (void *tdata)
{
struct thdata *data = tdata;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
pthread_cond_wait(data->cond, data->mutex);
printf("turns: value read: %f\n\n", *data->sensor_value);
pthread_mutex_unlock(data->mutex);
usleep(1000);
}
puts("turns: bye");
pthread_exit(NULL);
}
int main(void)
{
srand(time(NULL));
struct thdata thd[2];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// controlling vars
int run_rfs = 1;
int run_tof = 1;
float sensor_value;
thd[0].run = &run_rfs;
thd[1].run = &run_tof;
thd[0].mutex = &mutex;
thd[1].mutex = &mutex;
thd[0].cond = &cond;
thd[1].cond = &cond;
thd[0].sensor_value = &sensor_value;
thd[1].sensor_value = &sensor_value;
pthread_t th[2];
printf("Press ENTER to exit...\n");
pthread_create(th, NULL, reads_from_sensors, thd);
pthread_create(th + 1, NULL, turns_on_or_off, thd + 1);
getchar();
puts("Stopping threads...");
run_rfs = 0;
run_tof = 0;
pthread_join(th[0], NULL);
pthread_join(th[1], NULL);
return 0;
}
Output:
$ ./a
Press ENTER to exit...
read: value == -99.500000, sending signal
turns: value read: -99.500000
read: value == -25.200001, sending signal
turns: value read: -25.200001
read: value == 53.799999, sending signal
turns: value read: 53.799999
read: value == 20.400000, sending signal
turns: value read: 20.400000
Stopping threads...
read: bye
turns: value read: 20.400000
turns: bye
Note that in the example I only send the signal every 3 seconds (and do a long
sleep(1)) for testing purposes, otherwise the terminal would overflow immediately
and you would have a hard time reading the output.
See also: understanding of pthread_cond_wait() and pthread_cond_signal()
Your question is too generic. There are different multithread synchronization methods mutex, reader-writer locks, conditional variables and so on.
The easiest and most simple are mutex (mutual excluasion). They are pthread_mutex_t type variables. You first need to initialize them; you can do it in two ways:
assigning to the mutex variable the constant value PTHREAD_MUTEX_INITIALIZER
calling the funtion pthread_mutex_init
Then before reading or writing a shared variable you call the function int pthread_mutex_lock(pthread_mutex_t *mutex); and after exited the critical section you must release the critical section by calling int pthread_mutex_unlock(pthread_mutex_t *mutex);.
If the resource is busy the lock will block the execution of your code until it gets released. If you want to avoid that take a look at int pthread_mutex_trylock(pthread_mutex_t *mutex);.
If your program has much more reads than writes on the same shared variable, take a look at the Reader-Writer locks.
I am new in threads in c. My code has a thread that increasing a counter and occasionally(randomly) another thread reads that counter. I used mutex in this code but my code always gives me value equal to 1. Although I used pthread_mutex_unlock but it seems the value becomes lock for ever. what should I do to solve the problem?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <pthread.h>
///////////////////////////
long int count=0;
int RunFlag=0;
pthread_mutex_t mtx;
void *readfun(void *arg)
{
while (RunFlag==0)
{
pthread_mutex_lock(&mtx);
count=count+1;
pthread_mutex_unlock(&mtx);
}
}
void *printfun(void *arg)
{
int RadnTime=0;
for (int j=0;j<4;j++)
{
RadnTime=rand()%3+1;
sleep(RadnTime);
printf("The current counter after %d seconds is: ",RadnTime);
pthread_mutex_lock(&mtx);
printf("%d\n",count);
pthread_mutex_unlock(&mtx);
}
}
void main ()
{
pthread_t thread1;
pthread_t thread2;
pthread_mutex_init(&mtx, NULL);
pthread_create(&thread1,NULL,readfun,NULL);
pthread_create(&thread2,NULL,printfun,NULL);
//stop the counter
RunFlag=1;
pthread_exit(NULL);
}
You are setting RunFlag immediately after the two threads are created, so readfun barely has any time to execute. RunFlag=1; should be at the end of printfun.
As far as I know, reading from and writing to RunFlag isn't guaranteed to be atomic, so access to it should be protected as well. I don't see a problem happening here (given the values in question), but you are entering undefined behaviour territory.
Your functions don't return anything even though they are declared as returning void*. Add return NULL; to them.
Finally, the second %d should be %ld since count is a long int.
Note that
pthread_mutex_t mtx;
pthread_mutex_init(&mtx, NULL);
can be replaced with
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
1) You also have data race as two are accessing RunFlag. So, you need to protect it with synchronization primitive (such as mutex or use a semaphore).
But you don't need the RunFlag for this purpose. Since you can use an infinite loop in readfun() thread and then simply call _exit() from printfun() thread to exit the whole process.
2) Thread functions must return a pointer to satisfy by pthread_create()'s requirement. But you thread functions don't return anything. You can add return NULL; at the end of both thread functions.
Be aware of signed integer overflow as count could potentially overflow.
I'm trying to use mutex instead of semaphore because I want semaphore behavior but binary (not counting). (Perhaps you'll notice I'm in the early stages of trying to simulate the Sleeping Barber algorithm.) This is my code:
#include <stdio.h>
#include <pthread.h>
int main( int argc, char** argv ) {
int freeSeats = 6;
pthread_mutexattr_t mutexAttr;
pthread_mutex_t custWaiting, wrAccess, barberReady;
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&custWaiting, &mutexAttr);
pthread_mutex_init(&wrAccess, &mutexAttr);
pthread_mutex_init(&barberReady, &mutexAttr);
pthread_mutex_lock(&custWaiting);
pthread_mutex_lock(&custWaiting);
pthread_mutex_lock(&custWaiting);
fprintf(stdout, "got here\n\n");
return 0;
}
When I execute for the first time, this runs as expected (thread is blocked, command line hangs while my program waits to be able to lock). When I kill the program, and run it a second time, it prints "got here", which it should not. Why would this only fail on the second (and all following) attempts, but not on the first?
Bafflingly, if I modify the code as follows (only the init and lock lines):
#include <stdio.h>
#include <pthread.h>
int main( int argc, char** argv ) {
int freeSeats = 6;
pthread_mutexattr_t mutexAttr;
pthread_mutex_t custWaiting, wrAccess, barberReady;
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
int y = pthread_mutex_init(&custWaiting, &mutexAttr);
y = pthread_mutex_init(&wrAccess, &mutexAttr);
y = pthread_mutex_init(&barberReady, &mutexAttr);
int x = pthread_mutex_lock(&custWaiting);
x = pthread_mutex_lock(&custWaiting);
x = pthread_mutex_lock(&custWaiting);
fprintf(stdout, "got here\n\n");
return 0;
}
... then it works every time. The reason this is so maddening is because I can't check error codes on pthread_mutex_whatever() because it doesn't fail when I try to catch the error codes. I don't want to assign the return values to ints if I'm not going to use them. As you can see, I'm not using x or y at all; just assigning return values of init and lock functions to them. So why does that change the behavior of the mutexes so drastically? Or am I missing something else? What am I doing wrong?
You should init your mutexattr by calling :
pthread_mutexattr_init(&mutexAttr);
And also set the type :
pthread_mutexattr_settype(amutexAttr, PTHREAD_MUTEX_NORMAL);
otherwise your code depends on the stack content, and the mutex can be of recursive type, which is why you see random behaviour. If you set the type to PTHREAD_MUTEX_DEFAULT, behaviour is undefined, while PTHREAD_MUTEX_NORMAL gives you deadlock
You are taking the lock on the same mutex three times, this is undefined behavior unless you declare your mutex to be recursive. Probably you meant to lock the three different mutexes.
The undefined behavior means that anything can happen, including the behavior that you observe, here.
To set the properties of a mutex, you'd have to change the properties of the mutex attribute with pthread_mutexattr_settype. There are basically two types that augment the default behavior, PTHREAD_MUTEX_ERRORCHECK and PTHREAD_MUTEX_RECURSIVE. The first would block if you try to re-lock, the second can be used to lock and unlock multiple times.
The default behavior is leaving this undefined, because implementing such checks are costly.
I have written a C program that uses two threads for reading and writing. I have declared the variable which are accessed by both the threads as Global. How to avoid the use of global variables in this case.
Please look into following methods of pthread library in C for having exclusive access of Shared Global variables in C:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Similarly, you can look into Semaphores for synchronizing the use of global variables in C threads.
HOw to avoid the use of global variables in this case.
There is no need to avoid global variables. Only thing you have to consider is valid data by some lock mechanism.
Putting all global variables in to a struct is for readability and code control when your project grows.
I suggest you to use mutex lock.. Here is an modified sample code.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
double *a;
double *b;
double sum;
int veclen;
} DOTDATA;
/* Define globally accessible variables and a mutex */
#define NUMTHRDS 4
#define VECLEN 100
DOTDATA dotstr;
pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;
void *dotprod(void *arg)
{
/* Define and use local variables for convenience */
int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;
len = dotstr.veclen;
start = offset*len;
end = start + len;
x = dotstr.a;
y = dotstr.b;
/*
Perform the dot product and assign result
to the appropriate variable in the structure.
*/
mysum = 0;
for (i=start; i<end ; i++)
{
mysum += (x[i] * y[i]);
}
/*
Lock a mutex prior to updating the value in the shared
structure, and unlock it upon updating.
*/
pthread_mutex_lock (&mutexsum);
dotstr.sum += mysum;
pthread_mutex_unlock (&mutexsum);
pthread_exit((void*) 0);
}
/*
The main program creates threads which do all the work and then
print out result upon completion. Before creating the threads,
the input data is created. Since all threads update a shared structure,
we need a mutex for mutual exclusion. The main thread needs to wait for
all threads to complete, it waits for each one of the threads. We specify
a thread attribute value that allow the main thread to join with the
threads it creates. Note also that we free up handles when they are
no longer needed.
*/
int main (int argc, char *argv[])
{
long i;
double *a, *b;
void *status;
/* Assign storage and initialize values */
a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
for (i=0; i<VECLEN*NUMTHRDS; i++)
{
a[i]=1.0;
b[i]=a[i];
}
dotstr.veclen = VECLEN;
dotstr.a = a;
dotstr.b = b;
dotstr.sum=0;
pthread_mutex_init(&mutexsum, NULL);
for(i=0; i<NUMTHRDS; i++)
{
/*
Each thread works on a different set of data.
The offset is specified by 'i'. The size of
the data for each thread is indicated by VECLEN.
*/
pthread_create(&callThd[i], NULL, dotprod, (void *)i);
}
/* Wait on the other threads */
for(i=0; i<NUMTHRDS; i++)
{
pthread_join(callThd[i], &status);
}
/* After joining, print out the results and cleanup */
printf ("Sum = %f \n", dotstr.sum);
free (a);
free (b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
}
Do you truly need a shared variable, or do you actually need 2 copies of the same data for each thread? If so, instead of declaring it global, pass it as an argument to the thread at creation.
If it truly needs to be shared, it will need to be protected by a mutex. You can still also do away with the global variable if you bundle the shared variable into a struct along with the mutex and pass it along to the threads as an argument at creation.
I think you're asking how to avoid having your threads accessing globals by passing them their work-data during startup.
Please see the last parameter to pthread_create, which allows you to define a user-defined custom pointer that can be anything you want. Use that to pass data (such as a struct address or even by-value so long as the value can fit in the platform's size of a void pointer.
For example, a parent can send a child thread data by doing such:
Data data;
pthread_create(&thrd, NULL, threadProc, &data);
The child proc would reference this by:
void *threadProc(void *pv)
{
Data *pData = (Data*)pv;
.. use data here...
pthread_exit(NULL);
}
I hope this makes sense, and hope it helps you understand how to pass data to a thread proc, which was what I think your question is.
If you want each thread to have a separate copy of the variable, declare the variables as thread local.
You can make structs. I usually to use a struct called globalArgs where I put all there global variables.
Something like this:
static typedef struct {
int foo;
int baa;
} globalargs;
Or, you can pass all values as parameters to functions that needs of.