Understanding concurrency better (with locks) - c

I'm trying to understand concurrency and using locks better, but this dummy example I made is throwing me off:
int i = 0;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_create(&p2, NULL, (void*) boo, NULL);
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
If I understand correctly, the i = i + 1; in both foo() and bar() can cause some unexpected behaviour. One unexpected behaviour is that we'll get both "foo: 0" and "bar: 0" since it's possible that a context switch happened right before the i = i + 1; and so n is always 0. I think the expected behaviour is that "foo: 0" "bar: 1" or "bar: 0" "foo: 1" (please correct me if I'm wrong).
To fix this, I added locks:
int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
printf("Locking foo\n");
pthread_mutex_lock(&lock);
printf("Locked foo\n");
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked foo\n");
printf("Locking boo\n");
pthread_mutex_lock(&lock);
printf("Locked boo\n");
pthread_create(&p2, NULL, (void*) boo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked boo\n");
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
I think this would fix the unexpected results, but I got a surprising output when I ran this:
Locking foo
Locked foo
Unlocked foo
Locking boo
Locked boo
foo: 0
Unlocked boo
boo: 1
main: 2
It looks like the program locked the first thread that calls foo() and then immediately unlocked it without actually executing the printf? It then goes on to locking the thread that calls boo() and does weird things out of order. Can someone explain this behaviour? I would of thought the output would have looked like:
Locking foo
Locked foo
foo: 0
Unlocked foo
Locking boo
Locked boo
boo: 1
Unlocked boo
main: 2

Your choice of wording betrays a likely serious misunderstanding:
It looks like the program locked the first thread that calls foo()
Programs do not lock threads. Rather, threads acquire locks (or, equivalently, threads lock mutexes). That can include a program's main thread, too. Mutual exclusion is achieved among cooperating (!) threads by the fact that only one thread can hold any particular lock (mutex) at a time.
Thus, if thread B has a given mutex locked when thread A attempts to acquire it then thread A's acquisition attempt will block (the return of the pthread_mutex_lock() call will be delayed). Thread A will not proceed until it does acquire the mutex. Thus, the boundaries of critical regions are defined by calls to pthread_mutex_lock() and pthread_mutex_unlock() on the same mutex. Approximately speaking, every participating thread must acquire the appropriate mutex before accessing shared shared variables, and each one must release the mutex when it is done to allow other threads to acquire it in turn.
Other answers have already presented details of how that might look in your example program.

The locking should take place in the functions like here:
#include <stdio.h>
#include <pthread.h>
int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void foo() {
printf("Locking foo\n");
pthread_mutex_lock(&lock);
printf("Locked foo\n");
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("Unlocked foo\n");
printf("foo: %d\n", n);
}
void boo() {
printf("Locking boo\n");
pthread_mutex_lock(&lock);
printf("Locked boo\n");
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("Unlocked boo\n");
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_create(&p2, NULL, (void*) boo, NULL);
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
This way, when one function locks, the other function will be blocked until the lock is unlocked.

You are using the locks incorrectly. You lock the mutex, start the thread, and unlock it. The thread runs without any knowledge of the locking operations. Use the lock in the functions sharing memory:
void foo() {
pthread_mutex_lock(&lock);
int n = i;
i = i + 1;
pthread_mutex_unlock(&lock);
printf("foo: %d\n", n);
}
Do the same with boo function.

Related

How to make a pthread signal another that it can continue executing?

I have three integers (a, b and c), and I'd like to create two threads (POSIX pthreads) to access them in this particular sequence to keep the results consistent:
Thread 1 | Thread 2
---------------------
a=1 b=5
c=7
c=c+10
b=a+c*2
a=b+b*10
That is, c=c+10 in thread2 must wait until c=7 in thread1 finishes. Also a=b+b*10 in thread1 must wait until b=a+c*2 in thread2 finished.
I have tried using mutexes, but it does not work as I intend (code below). If thread2 starts first, it can lock mutex1 before thread1 has locked it, so the sequencing is lost. Locking the mutex from the main thread is not an option, as it would yield an undefined behavior (mutex locked and then unlocked by a different thread). I've also tried using conditional variables, but a similar problem arises: a signal can happen before the associated wait.
#include <pthread.h>
#include <stdio.h>
int a, b, c;
pthread_mutex_t mutex1, mutex2 = PTHREAD_MUTEX_INITIALIZER;
void *thread1(void *arg) {
pthread_mutex_lock(&mutex1);
a = 1;
c = 7;
pthread_mutex_unlock(&mutex1);
pthread_mutex_lock(&mutex2);
a = b + b*10;
pthread_exit(NULL);
}
void *thread2(void *arg) {
pthread_mutex_lock(&mutex2);
b = 5;
pthread_mutex_lock(&mutex1);
c = c + 10;
b = a + c*2;
pthread_mutex_unlock(&mutex2);
pthread_exit(NULL);
}
int main() {
pthread_t t1, t2;
if(pthread_create(&t1, NULL, thread1, NULL)) {
fprintf(stderr, "Error creating Thread 1\n");
return 0;
}
if(pthread_create(&t2, NULL, thread2, NULL)) {
fprintf(stderr, "Error creating Thread 2\n");
return 0;
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return a;
}
My question is, what is correct way to achieve the thread sequencing I want using pthreads? Thanks in advance.
pthread_mutex_t mutex1, mutex2 = PTHREAD_MUTEX_INITIALIZER
Only initializes the second one; but that is a nit. Depending upon the system you are running, you might not notice this, because mutex1 is uninitialized, thus the operations on it may be failing, or the initializer constant could be zero....
The signal/wait problem is not a problem -- you wait upon a condition protected by a mutex, in this pattern:
lock();
while (check() == false) {
wait();
}
func();
signal();
unlock();
so thread1’s check would be true, and func would be c = 7
while thread2’s check would be (c == 7) and func would be c += 10

two threads, first adds second substracts

This is a classic example of mutex locks. I don't know why the following code doesn't work, ie. it doesn't print "ctr = 0" every time (but, for example, ctr = 535).
int ctr;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void * add (void * arg_wsk)
{
int i;
for (i = 0; i < 100000; i++) {
pthread_mutex_lock (&m);
ctr++;
pthread_mutex_unlock (&m);
}
return(NULL);
}
void * sub(void * arg_wsk)
{
int i;
for (i = 0; i < 100000; i++) {
pthread_mutex_lock (&m);
ctr--;
pthread_mutex_unlock (&m);
}
return(NULL);
}
int main()
{
pthread_t tid1, tid2;
int i;
void *res;
ctr = 0;
pthread_mutex_init(&m, NULL);
pthread_create(&tid1, NULL, add, NULL);
pthread_detach(tid1);
pthread_create(&tid2, NULL, sub, NULL);
pthread_detach(tid2);
pthread_join(tid1, &res);
pthread_join(tid2, &res);
pthread_mutex_destroy(&m);
printf("ctr = %d", ctr);
pthread_exit(NULL);
}
I think you are misusing the POSIX API. If you detach the threads, you shouldn't join them. Remove the detach and see if this improves things. I think you'll see that main() now blocks until the threads have completed.
Note also, from the link for the join call
ESRCH No thread could be found corresponding to that specified by the
given thread ID.
If you're lucky, you'll hit this. If you're not lucky, crazy things will happen. Don't mix detach and join calls on the same thread.
https://computing.llnl.gov/tutorials/pthreads/#Joining
The value of your counter ctr depends on both the threads completing their full execution.
According to pthread_detach(3)
Once a thread has been detached, it can't be joined with
pthread_join(3) or be made joinable again.
If you remove pthread_detach call from your program, you will get the expected output.
Also, consider explicitly creating your thread joinable(or detached) for portability.

pthreads program doesn't behave well

I'm trying to make a simple program using pthreads, want to make 6 threads and pass index to all of them. here's the code:
#include <pthread.h>
#include <stdio.h>
#define num_students 6
void thread_starter();
int main() {
pthread_t thread1[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
}
sleep(1);
}
void thread_starter(void* a) {
printf("Thread %i \n", *((int*)a));
}
And the output:
Thread 2
Thread 3
Thread 2
Thread 4
Thread 5
Thread 5
why do they have commmon names? what's wrong?
Thanks
You're passing a stack address from the main thread into all the child threads. There is no guarantee when these threads will be scheduled so you have no way of knowing whether the main thread will have updated its stack variable by the time each child gets around to reading it.
To avoid this, you need to allocate memory for the data being passed to each thread.
The easiest way to do this in your example is to use another automatic variable to store the data being passed to the new threads
void thread_starter(void* a);
int main() {
pthread_t thread1[num_students];
int thread_data[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
thread_data[i] = i;
pthread_create(&thread1[i], NULL, thread_starter, &thread_data[i]);
}
sleep(1);
}
Note also that you can avoid having to cast thread_starter if you give it the correct signature in your forward declaration.
For more complex programs you may need to dynamically allocate memory for each thread instead, passing ownership of that memory to the new threads.
int main() {
pthread_t thread1[num_students];
int i = 0;
for(i = 0; i<num_students; i++) {
int* data = malloc(sizeof(*data));
*data = i;
pthread_create(&thread1[i], NULL, thread_starter, data);
}
sleep(1);
}
void thread_starter(void* a) {
printf("Thread %i \n", *((int*)a));
free(a);
}
Finally, using sleep(1) isn't a very rigorous way of ensuring that all your threads will be run. It'd be better to use pthread_join instead
for(i = 0; i<num_students; i++) {
pthread_join(thread1[i], NULL);
}
sleep is not the correct tool to wait for spawned threads, use pthread_join for this.
Your main function terminating is equivalent to calling exit for the whole program and killing all the other threads.
Try This for Variation
void thread_starter(void* a) {
// Put a sleep(1) Here and see you will get even bizarre results
printf("Thread %i \n", *((int*)a));
}
Ok the problem here is of course
the race condition at this point here
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
lets say the first thread is created and the value at q is 0
now assume that before executing the statement Here
printf("Thread %i \n", *((int*)a));
if the main thread loops further and executes this statement here
int q = i;
again, then the q value changes (because its a reference) hence the problem
well one way to avoid this is to copy this reference variable in a local variable in thread routine also use mutex.
Sorry I was on a Hurry some more tips from my side
#define num_students 6
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // A Global Mutex
Will aquire a lock Here
pthread_mutex_lock( &mutex );
printf("\n Got Mutex %d\n", i);
int q = i;
pthread_create(&thread1[i], NULL, (void *) &thread_starter, (void *)&q);
and will release the lock Here in child Routine
int i = *((int*)a);
sleep(1);
pthread_mutex_unlock( &mutex );
printf("Thread %i \n", i);
P.S - Remove un necessary Prints and Sleeps where ever not applicable

printf with pthreads in C

I am working with pthreads right now doing the producer/consumer problem. I am currently just trying to get the producer working and using printf statements to see where my issues are. The problem is the code compiles just fine but when I run it, it doesn't do anything but seems to run just fine. I have tried setting my first line to a printf statement but even that does not print. I have tried using fflush as well and I am running out of ideas. My question why would even the first printf statement get skipped?
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
void *producer();
pthread_mutex_t lock;
pthread_cond_t done, full, empty;
int buffer[10];
int in = 0, out = 0;
int min = 0, max = 0, numOfItems = 0, total = 0;
double avg;
void *producer() {
srand(time(NULL));
int n = rand();
int i;
for(i = 0; i < n; i++)
{
int random = rand();
pthread_mutex_lock(&lock);
buffer[in++] = random;
if(in == 10)
{
pthread_cond_signal(&full);
printf("Buffer full");
pthread_mutex_unlock(&lock);
sleep(1);
}
}
pthread_exit(NULL);
}
void *consumer() {
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
printf("test");
//Create threads and attribute
pthread_t ptid, ctid;
pthread_attr_t attr;
//Initialize conditions and mutex
pthread_cond_init(&full, NULL);
pthread_cond_init(&empty, NULL);
pthread_cond_init(&done, NULL);
pthread_mutex_init(&lock, NULL);
//Create joinable state
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&ptid, &attr,(void *)producer,NULL);
pthread_create(&ctid, &attr,(void *)consumer,NULL);
pthread_join(ptid,NULL);
pthread_join(ctid,NULL);
printf("Program Finished!");
pthread_exit(NULL);
}
man pthread_mutex_init
pthread_mutex_init initializes the mutex object pointed to by mutex
according to the mutex attributes specified in mutexattr. If mutexattr
is NULL, default attributes are used instead.
The LinuxThreads implementation supports only one mutex attributes, the
mutex kind... The kind of a mutex determines whether it can be locked again by
a thread that already owns it. The default kind is fast...
If the mutex is already locked by the calling thread, the behavior of
pthread_mutex_lock depends on the kind of the mutex. If the mutex is of
the fast kind, the calling thread is suspended until the mutex is
unlocked, thus effectively causing the calling thread to deadlock.
That's what happens to your producer: it deadlocks in the call
pthread_mutex_lock(&lock);
- except in the unlikely case n < 2 - thus producing no output.

multithreading(pthread) compete code

#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
int global;
int i = 30;
int j = 30;
int k = 30;
pthread_mutex_t mutex;
void* child1(void* arg)
{
while(k--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from child1\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
}
void* child2(void* arg)
{
while(j--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from child1\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid1, tid2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid1, NULL, child1, NULL);
pthread_create(&tid2, NULL, child2, NULL);
while(i--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from main\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
return 0;
}
I'm new to pthread and multithreading, the result of this code is from main xx and child1 appeared rarely, the three threads never appear together, what's the problem?
Most of time in the critical sections will be spent in the printf calls. You might try:
{
int local;
pthread_mutex_lock(& mutex);
local = ++global;
pthread_mutex_unlock(& mutex);
printf("from <fn>\n%d\n", local);
}
This still doesn't give any guarantee of 'fairness' however, but the printf call is very likely to use a system call or I/O event that will cause the scheduler to kick in.
Your program is similar to the Dining Philosophers Problem in many respects. You don't want any thread to 'starve', but you have contention between threads for the global counter, and you want to enforce an orderly execution.
One suggestion in code replace printf("from child1\n"); to printf("from child2\n"); in void* child2(void* arg) function. And if you want ensure all threads to complete please add the following lines at end of main function.
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
I think you should use 3 differents mutex , by the way use pconditional control in order to avoid having unsafe access

Resources