• Uncategorized

About c : How-to-create-2-threads-first-one-take-input-numbers-and-the-second-one-collect-them

Question Detail

Here is my code. The sum part is not working. I need some controls for that but I couldn’t do it.

I tried make number variable number=-1, but that also didn’t work and I had an infinite loop.

By the way this is my first question that i ask here, so i can make mistakes. Sorry for that.


#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdbool.h>

int number = 0, sum = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *threadFunction1()
{
    pthread_mutex_lock(&mutex);
    while (true)
    {
        printf("Number:");
        scanf("%d", &number);
        if (number == 0) break;
    }

    pthread_exit(NULL);
}

void *threadFunction2()
{
    pthread_mutex_lock(&mutex);
    while (true)
    {
        sum += number;
        printf("Sum is:%d\n", sum);
        if (number == 0) break;
    }
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

int main()
{
    pthread_t thread1, thread2;
    int case1, case2;

    case1 = pthread_create(&thread1, NULL, threadFunction1, NULL);
    case2 = pthread_create(&thread2, NULL, threadFunction2, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("It's over..\n");
    pthread_mutex_destroy(&mutex);
    return 0;
}

Here is the output

Question Answer

An immediately obvious issue is that threadFunction1 locks the mutex

pthread_mutex_lock(&mutex);
while (true)
{
    printf("Number:");
    scanf("%d", &number);
    if (number == 0) break;
}

pthread_exit(NULL);

but never unlocks it. It is impossible to share a resource when one thread takes complete control over it.

The next issue is that the locking and unlocking of the mutex occurs outside of the while loop.

pthread_mutex_lock(&mutex);
while (true)
{
    sum += number;
    printf("Sum is:%d\n", sum);
    if (number == 0) break;
}
pthread_mutex_unlock(&mutex);

This means whichever thread gets CPU time first will lock the mutex, and enter a potentially long running loop, only unlocking the mutex when that loop ends:

If threadFunction1 is the first to lock the mutex, this loop lasts until the user enters 0, wherein the loop is broken and the thread is terminated. After this, threadFunction2 never gets a turn, due to the lack of an unlock.

If threadFunction2 is the first to lock the mutex, this loop is broken after during its first iteration, as number is initialized to 0. After this the thread is terminated, and threadFunction1 would get a turn, since the mutex is unlocked.

The final issue is that a single mutex alone is not the correct tool to use here.

Even moving the locks and unlocks inside the loop, so that each thread has a chance to lock the mutex, do some work, and then unlock, there is no guarantee that both threads will get equal access to the lock.

while (true)
{
    pthread_mutex_lock(&mutex);
    sum += number;
    printf("Sum is:%d\n", sum);
    pthread_mutex_unlock(&mutex);
    if (number == 0) break;
}

In fact, the opposite will probably occur. By default, it is very likely for one thread to be granted some CPU time, lock the mutex, do some work, unlock the mutex, and with its remaining time immediately lock the mutex again.

So we need a way to make two threads evenly share a resource.

One way is, instead of using a mutex, to use two semaphores to create a lockstep. This means one thread waits to for a semaphore which the other thread posts, and vice versa.

Note that in main we start the to_read semaphore with a value of 1, meaning the scanning thread effectively “goes first”.

#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

static int number = 0;
static int sum = 0;
static sem_t to_read;
static sem_t to_write;

static void *scanning(void *arg) {
    while (true) {
        sem_wait(&to_read);

        printf("Enter a number: ");

        if (1 != scanf("%d", &number))
            number = 0;

        sem_post(&to_write);

        if (number == 0)
            break;
    }

    return NULL;
}

static void *adding(void *arg) {
    while (true) {
        sem_wait(&to_write);

        sum += number;
        printf("Sum is: %d\n", sum);

        sem_post(&to_read);

        if (number == 0)
            break;
    }

    return NULL;
}

int main(void) {
    pthread_t thread1, thread2;

    sem_init(&to_read, 0, 1);
    sem_init(&to_write, 0, 0);

    pthread_create(&thread1, NULL, scanning, NULL);
    pthread_create(&thread2, NULL, adding, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    puts("It's over...");

    sem_destroy(&to_read);
    sem_destroy(&to_write);
}

Note that this will surely perform worse than a single threaded loop in main, doing the same amount of work, due to the overhead of context switching. That said, it is just a toy example.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.