ScholarQuill logoScholarQuillUniversity Notes
  • Notes
  • Past Papers
  • Blogs
  • Todo
Login
ScholarQuill logoScholarQuillUniversity Notes
Login
NotesPast PapersBlogsTodo
More
SubjectsDiscussionCGPA CalculatorGPA CalculatorStudent PortalCourse Outline
About
About usPrivacy PolicyReportContact
Notes
Past Papers
Blogs
Todo
Analytics
    Current Subject
    🧩
    Parallel & Distributed Computing
    COMP3139
    Progress0 / 33 topics
    Topics
    1. Introduction to Parallel and Distributed Systems2. Why Use Parallel and Distributed Systems?3. Speedup and Amdahl's Law4. Hardware Architectures: Multi Processors (Shared Memory)5. Hardware Architectures: Networks of Workstations (Distributed Memory)6. Hardware Architectures: Clusters (Latest Variation)7. Software Architectures: Threads and Shared Memory8. Software Architectures: Processes and Message Passing9. Software Architectures: Distributed Shared Memory (DSM)10. Software Architectures: Distributed Shared Data (DSD)11. Parallel Algorithms12. Concurrency and Synchronization13. Data and Work Partitioning14. Common Parallelization Strategies15. Granularity16. Load Balancing17. Examples of Parallel Algorithms: Parallel Search18. Examples of Parallel Algorithms: Parallel Sorting19. Shared-Memory Programming20. Threads in Shared-Memory Programming21. P Threads22. Locks and Semaphores23. Distributed-Memory Programming24. Message Passing25. Map Reduce26. Distributed-Memory Programming with PI27. Google's Map Reduce28. Hadoop29. Other Parallel Programming Systems30. Tread Marks31. Distributed Shared Memory32. Aurora: Scoped Behavior and Abstract Data Types33. S Enterprise: Process Templates
    COMP3139›P Threads
    Parallel & Distributed ComputingTopic 21 of 33

    P Threads

    8 minread
    1,291words
    Intermediatelevel

    PThreads (POSIX Threads)

    PThreads (POSIX Threads) is a widely used threading library for multi-threaded programming, providing a standard interface for managing and controlling threads on Unix-like operating systems (e.g., Linux, macOS). PThreads is part of the POSIX (Portable Operating System Interface) standard, which is designed to ensure that programs can be written to work on different Unix-based systems.

    PThreads provides low-level control over thread creation, synchronization, and management, offering a powerful toolset for writing high-performance, parallelized programs. It is particularly suitable for developers who need fine-grained control over how threads are managed in shared-memory systems.


    1. Basic Concepts of PThreads

    PThreads allows you to create and manage threads in a multi-threaded application, where each thread runs concurrently. In shared-memory systems, all threads in a process share the same memory space, so they can communicate through shared data structures. However, to avoid conflicts or corruption of data, synchronization mechanisms are necessary.

    Key Concepts:

    • Thread Creation: PThreads provides the ability to create and manage threads using functions like pthread_create.
    • Thread Synchronization: To prevent race conditions, PThreads provides synchronization mechanisms such as mutexes, condition variables, and barriers.
    • Thread Joining: After a thread completes its task, it can be joined with the main thread or other threads using pthread_join.
    • Thread Termination: Threads can terminate when they complete their task, or they can be explicitly canceled.
    • Thread Attributes: PThreads allow setting attributes for threads, such as scheduling policies, stack size, and whether they are joinable or detached.

    2. Thread Creation

    The pthread_create() function is used to create a new thread. This function takes four arguments:

    • A pointer to a pthread_t variable (which represents the thread).
    • A pointer to a pthread_attr_t variable (optional, for thread attributes; can be NULL for default settings).
    • A function pointer to the function the thread should execute.
    • A single argument that can be passed to the thread function.

    Syntax:

    #include <pthread.h>
    
    int pthread_create(pthread_t *thread, 
                       const pthread_attr_t *attr, 
                       void *(*start_routine)(void *), 
                       void *arg);
    

    Example: Creating a Thread in PThreads

    #include <pthread.h>
    #include <stdio.h>
    
    // Function that will be executed by the thread
    void* thread_func(void* arg) {
        printf("Hello from thread! Arg: %d\n", *(int*)arg);
        return NULL;
    }
    
    int main() {
        pthread_t thread;  // Declare a thread variable
        int arg = 42;
    
        // Create a thread and pass 'arg' as an argument
        pthread_create(&thread, NULL, thread_func, (void*)&arg);
    
        // Wait for the thread to finish
        pthread_join(thread, NULL);
    
        return 0;
    }
    

    In this example, the main thread creates a new thread that executes the function thread_func, passing an integer argument to it. The pthread_join function waits for the newly created thread to finish before continuing.


    3. Thread Synchronization Mechanisms

    PThreads provides several synchronization mechanisms to ensure that threads access shared resources safely and avoid issues like race conditions (when two or more threads attempt to modify the same data simultaneously).

    a. Mutexes (Mutual Exclusion)

    A mutex is a synchronization primitive used to protect shared resources from being accessed simultaneously by multiple threads. A thread must lock the mutex before accessing a shared resource and unlock it after finishing the access.

    • pthread_mutex_init(): Initializes a mutex.
    • pthread_mutex_lock(): Locks a mutex.
    • pthread_mutex_unlock(): Unlocks a mutex.

    Example of using a mutex:

    #include <pthread.h>
    #include <stdio.h>
    
    pthread_mutex_t lock;  // Mutex declaration
    
    void* thread_func(void* arg) {
        pthread_mutex_lock(&lock);  // Lock the mutex
        printf("Thread is accessing shared resource\n");
        pthread_mutex_unlock(&lock);  // Unlock the mutex
        return NULL;
    }
    
    int main() {
        pthread_t thread1, thread2;
    
        pthread_mutex_init(&lock, NULL);  // Initialize mutex
    
        // Create two threads that will access shared resource
        pthread_create(&thread1, NULL, thread_func, NULL);
        pthread_create(&thread2, NULL, thread_func, NULL);
    
        pthread_join(thread1, NULL);  // Wait for thread1 to finish
        pthread_join(thread2, NULL);  // Wait for thread2 to finish
    
        pthread_mutex_destroy(&lock);  // Destroy mutex
        return 0;
    }
    

    In this example, the mutex ensures that the shared resource is accessed by only one thread at a time.

    b. Condition Variables

    Condition variables allow threads to wait for certain conditions to be met. For example, one thread can wait until another thread notifies it that it can continue. This is useful for producer-consumer problems or scenarios where threads need to wait for an event to occur.

    • pthread_cond_init(): Initializes a condition variable.
    • pthread_cond_wait(): Makes a thread wait on the condition variable.
    • pthread_cond_signal(): Signals one thread waiting on the condition variable.
    • pthread_cond_broadcast(): Signals all threads waiting on the condition variable.

    Example of using condition variables:

    #include <pthread.h>
    #include <stdio.h>
    
    pthread_mutex_t lock;
    pthread_cond_t cond;
    
    void* producer(void* arg) {
        pthread_mutex_lock(&lock);
        printf("Producer is producing\n");
        pthread_cond_signal(&cond);  // Signal the consumer to proceed
        pthread_mutex_unlock(&lock);
        return NULL;
    }
    
    void* consumer(void* arg) {
        pthread_mutex_lock(&lock);
        pthread_cond_wait(&cond, &lock);  // Wait for signal from producer
        printf("Consumer is consuming\n");
        pthread_mutex_unlock(&lock);
        return NULL;
    }
    
    int main() {
        pthread_t prod, cons;
    
        pthread_mutex_init(&lock, NULL);
        pthread_cond_init(&cond, NULL);
    
        pthread_create(&prod, NULL, producer, NULL);
        pthread_create(&cons, NULL, consumer, NULL);
    
        pthread_join(prod, NULL);
        pthread_join(cons, NULL);
    
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    
        return 0;
    }
    

    In this example, the consumer thread waits for the producer thread to signal that it can start consuming.

    c. Barriers

    A barrier is a synchronization mechanism that makes threads wait until all threads reach the same point in the program. Once all threads have reached the barrier, they can continue execution.

    PThreads does not have a direct barrier function, but you can implement it using condition variables or other synchronization mechanisms. Alternatively, you can use a library like POSIX barrier synchronization (pthread_barrier_t), which is available in POSIX-compliant systems.


    4. Thread Joining and Detachment

    a. Joining Threads

    After creating a thread, you usually want to wait for it to finish before continuing with the main thread. This is done using pthread_join().

    pthread_join(thread, NULL);  // Wait for the thread to finish
    

    b. Detaching Threads

    A thread can be detached, meaning that it is independent, and the system will automatically clean up resources when the thread terminates. Detached threads do not need to be joined.

    • pthread_detach(): Marks a thread as detached.

    Example:

    pthread_detach(thread);  // Detach the thread
    

    5. Thread Attributes

    PThreads allows you to customize thread behavior using thread attributes. These attributes can define properties such as the thread's scheduling policy, stack size, and whether it should be joinable or detached.

    • pthread_attr_init(): Initializes a thread attribute object.
    • pthread_attr_setstacksize(): Sets the stack size for the thread.
    • pthread_attr_setdetachstate(): Specifies whether the thread will be joinable or detached.

    Example of setting thread attributes:

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, 1024 * 1024);  // Set stack size to 1MB
    
    pthread_create(&thread, &attr, thread_func, NULL);
    

    6. Thread Cancellation

    PThreads also supports thread cancellation, which allows one thread to terminate another. This can be useful in certain situations, but it should be used carefully to avoid issues like resource leaks.

    • pthread_cancel(): Requests the cancellation of a thread.
    • pthread_setcancelstate(): Controls the thread's ability to be canceled.

    Example:

    pthread_cancel(thread);  // Cancel a thread
    

    7. Thread Safety and Best Practices

    While PThreads provides powerful tools for managing threads, developers need to take care when using these tools to avoid issues like race conditions, deadlocks, and excessive resource contention. Here are some best practices:

    • Minimize Shared State: Try to reduce the amount of shared data between threads to minimize the need for synchronization.
    • Use Fine-Grained Locks: Instead of locking large sections of code, lock smaller, more specific regions of code to improve concurrency.
    • Avoid Deadlocks: Ensure that threads acquire locks in a consistent order to avoid circular dependencies between threads.
    • **
    Previous topic 20
    Threads in Shared-Memory Programming
    Next topic 22
    Locks and Semaphores

    Past Papers

    Open this section to load past papers

    Click on Show Past Papers to see past papers.
    On This Page
      Reading Stats
      Est. reading time8 min
      Word count1,291
      Code examples0
      DifficultyIntermediate