现在的位置: 首页 > 综合 > 正文

Notes for Advanced Linux Programming – 4. Threads

2013年03月31日 ⁄ 综合 ⁄ 共 21863字 ⁄ 字号 评论关闭

4.  Threads

  • To use the POSIX standard thread API (pthreads), link libpthread.so
    to your program.

4.1. Thread Creation

  • Each thread in a process is identified by a thread ID,
    pthread_t.
  • The pthread_self function returns the thread ID of the current
    thread.
  • This thread IDs can be compared with the pthread_equal
    function.

if (!pthread_equal (pthread_self (),
other_thread))

    pthread_join
(other_thread, NULL);

  • each thread executes a thread function:

void * function(void *)

  • The pthread_create function creates a new thread.
  • A pointer to a pthread_t variable: store the thread ID of
    the new thread.
  • A pointer to a thread attribute object. You can pass NULL
    to use the default attributes.
  • A pointer to the thread function. void* (*) (void*)
  • A thread argument value of type void*.
  • Compile and link this program:

% cc -o thread-create thread-create.c
–lpthread

  • A thread exits in two ways.
  • return from the thread function. The function return value
    is the thread return value.
  • explicitly call pthread_exit. The argument to pthread_exit
    is the thread’s return value.
  • Create a Thread

#include <pthread.h>

#include <stdio.h>

/* Prints x’s to stderr. The parameter is
unused. Does not return. */

void* print_xs (void* unused)

{

    while (1)

        fputc (‘x’, stderr);

    return NULL;

}

/* The main program. */

int main ()

{

    pthread_t thread_id;

    /* Create a new thread. The new thread will run the print_xs function.
*/

    pthread_create (&thread_id, NULL, &print_xs, NULL);

    /* Print o’s continuously to stderr. */

    while (1)

        fputc (‘o’, stderr);

    return 0;

}

4.1.1. Passing Data to Threads

Listing 4.2 (thread-create2) Create Two
Threads

#include <pthread.h>

#include <stdio.h>

/* Parameters to print_function. */

struct char_print_parms

{

    /* The character to print. */

    char character;

    /* The number of times to print it. */

    int count;

};

/* Prints a number of characters to stderr,
as given by PARAMETERS,

which is a pointer to a struct
char_print_parms. */

void* char_print (void* parameters)

{

    /* Cast the cookie pointer to the right type. */

    struct char_print_parms* p = (struct char_print_parms*) parameters;

    int i;

    for (i = 0; i < p->count; ++i)

        fputc (p->character, stderr);

    return NULL;

}

/* The main program. */

int main ()

{

    pthread_t thread1_id;

    pthread_t thread2_id;

    struct char_print_parms thread1_args;

    struct char_print_parms thread2_args;

    /* Create a new thread to print 30,000 ’x’s. */

    thread1_args.character = ’x’;

    thread1_args.count = 30000;

    pthread_create (&thread1_id, NULL, &char_print,
&thread1_args);

    /* Create a new thread to print 20,000 o’s. */

    thread2_args.character = ’o’;

    thread2_args.count = 20000;

    pthread_create (&thread2_id, NULL, &char_print,
&thread2_args);

    return 0;

}

 

  • But there is a bug
  • Main thread creates the thread parameters as local
    variables and passes them to the threads.
  • If the main thread exits before the threads, the
    parameters will be deallocated.
  • But the threads are still accessing it.
  • Use join the wait for these threads to finish first.

4.1.2. Joining
Threads

pthread_join takes two arguments:

the thread ID of the thread to wait for

A pointer to a void* variable that will
receive the finished thread’s return value.

Revised Main Function for thread-create2.c

int main ()

{

    pthread_t thread1_id;

    pthread_t thread2_id;

    struct char_print_parms thread1_args;

    struct char_print_parms thread2_args;

    /* Create a new thread to print 30,000 x’s. */

    thread1_args.character = ’x’;

    thread1_args.count = 30000;

    pthread_create (&thread1_id, NULL, &char_print,
&thread1_args);

    /* Create a new thread to print 20,000 o’s. */

    thread2_args.character = ’o’;

    thread2_args.count = 20000;

    pthread_create (&thread2_id, NULL, &char_print,
&thread2_args);

    /* Make sure the first thread has finished. */

    pthread_join (thread1_id, NULL);

    /* Make sure the second thread has finished. */

    pthread_join (thread2_id, NULL);

    /* Now we can safely return. */

    return 0;

}

4.1.3. Thread Return Values

  • The second argument of pthread_join is the thread’s return
    value
  • Compute Prime Numbers in a Thread

#include <pthread.h>

#include <stdio.h>

/* Compute successive prime numbers (very
inefficiently). Return the

Nth prime number, where N is the value
pointed to by *ARG.
*/

void* compute_prime (void* arg)

{

    int candidate = 2;

    int n = *((int*) arg);

    while (1) {

        int factor;

        int is_prime = 1;

        /* Test primality by successive division. */

        for (factor = 2; factor < candidate; ++factor)

            if (candidate % factor == 0) {

                is_prime = 0;

                break;

            }

        /* Is this the prime number we’re looking for? */

        if (is_prime) {

            if (--n == 0)

            /* Return the desired prime number as the thread return value. */

                return (void*) candidate;

        }

        ++candidate;

    }

    return NULL;

}

int main ()

{

    pthread_t thread;

    int which_prime = 5000;

    int prime;

    /* Start the computing thread, up to the 5,000th prime number. */

    pthread_create (&thread, NULL, &compute_prime,
&which_prime);

    /* Do some other work here... */

    /* Wait for the prime number thread to complete, and get the result.
*/

    pthread_join (thread, (void*) &prime);

    /* Print the largest prime it computed. */

    printf(“The %dth prime number is %d./n”, which_prime, prime);

    return 0;

4.1.4. Thread Attributes

  • To specify customized thread attributes:
  • Create a pthread_attr_t object.
  • Call pthread_attr_init to initialize the attributes with
    default values.
  • Modify the attribute object to contain the desired
    attribute values.
  • Pass a pointer to the attribute object when calling
    pthread_create.
  • Call pthread_attr_destroy to release the attribute object.
    The pthread_attr_t variable itself is not deallocated and can be reinitialized
    with pthread_attr_init.
  • The detach state attribute.
  • A thread may be created as a joinable thread (the default)
    or as a detached thread.
  • A joinable thread is not automatically cleaned up it
    terminates until another thread calls pthread_join to obtain its return value.
  • A detached thread is cleaned up automatically when it
    terminates. Other thread can not pthread_join it to obtain its return value.
  • Use pthread_attr_setdetachstate to set the detach state in
    a thread attribute object.
  • Skeleton Program That Creates a Detached Thread

#include <pthread.h>

void* thread_function (void* thread_arg)

{

/* Do work
here... */

}

int main ()

{

    pthread_attr_t attr;

    pthread_t thread;

    pthread_attr_init (&attr);

    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

    pthread_create (&thread, &attr, &thread_function, NULL);

    pthread_attr_destroy (&attr);

    /* Do work here... */

    /* No need to join the second thread. */

    return 0;

}

4.2 Thread Cancellation

  • A thread can cancel another thread by calling
    phtread_cancel.
  • You should join the cancelled thread to free it resources.
  • The return value of a canceled thread is the special value
    given by PTHREAD_CANCELED
  • A thread can be in one of three states with regard to
    thread cancellation.
  • Asynchronously cancelable: The thread may be canceled at
    any point in its execution.
  • Synchronously cancelable: cancellation requests are queued
    until the thread reaches specific points in its execution.
  • Uncancelable: Attempts to cancel the thread are quietly
    ignored.
  • By default, a thread is synchronously cancelable
  • Call pthread_setcanceltype to set the cancellation type:
  • pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  • pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
  • pthread_setcanceltype (PTHREAD_CANCEL_DISABLE, NULL);

4.3 Thread-Specific Data

  • Each thread-specific data item has a key.
  • Each thread uses this key to access its own copy of the corresponding
    data item.
  • To create a new key and a new data item for each thread, call
    pthread_key_create.
  • The first argument is pthread_key_t
  • The second argument is a cleanup function which will be
    called when the thread exits.
  • Each thread can set its thread-specific value
    corresponding to that key by calling pthread_setspecific.
  • Call pthread_getspecific to retrieve a thread-specific
    data item.
  • Per-Thread Log Files Implemented with Thread-Specific Data

#include <malloc.h>

#include <pthread.h>

#include <stdio.h>

/* The key used to associate a log file
pointer with each thread. */

static pthread_key_t thread_log_key;

/* Write MESSAGE to the log file for the
current thread. */

void write_to_thread_log (const char*
message)

{

    FILE* thread_log = (FILE*) pthread_getspecific (thread_log_key);

    fprintf (thread_log, “%s/n”, message);

}

/* Close the log file pointer THREAD_LOG.
*/

void close_thread_log (void* thread_log)

{

    fclose ((FILE*)
thread_log);

}

void* thread_function (void* args)

{

    char thread_log_filename[20];

    FILE* thread_log;

    /* Generate the filename for this thread’s log file. */

    sprintf (thread_log_filename, “thread%d.log”, (int) pthread_self
());

    /* Open the log file. */

    thread_log = fopen (thread_log_filename, “w”);

    /* Store the file pointer in thread-specific data under
thread_log_key. */

    pthread_setspecific (thread_log_key, thread_log);

    write_to_thread_log (“Thread starting.”);

    /* Do work here... */

    return NULL;

}

int main ()

{

    int i;

    pthread_t threads[5];

    /* Create a key to associate thread log file pointers in thread-specific data. Use close_thread_log to clean up the file

pointers. */

    pthread_key_create (&thread_log_key, close_thread_log);

    /* Create threads to do the work. */

    for (i = 0; i < 5; ++i)

        pthread_create (&(threads[i]), NULL,
thread_function, NULL);

        /* Wait for all threads to finish. */

        for (i = 0; i < 5; ++i)

            pthread_join (threads[i], NULL);

    return 0;

}

4.3.1. Thread Clean-up

  • Linux provides cleanup handlers which is a function and
    should be called when a thread exits.
  • To register a cleanup handler, call pthread_cleanup_push.
  • pthread_cleanup_pop unregisters the cleanup handler.
  • pthread_cleanup_pop(0): just unregister the handler.
  • pthread_cleanup_pop(1): not only unregister the handler,
    but also call it.
  • Program Fragment Demonstrating a Thread Cleanup Handler

#include <malloc.h>

#include <pthread.h>

/* Allocate a temporary buffer. */

void* allocate_buffer (size_t size)

{

    return malloc
(size);

}

/* Deallocate a temporary buffer. */

void deallocate_buffer (void* buffer)

{

    free (buffer);

}

void do_some_work ()

{

    /* Allocate a temporary buffer. */

    void* temp_buffer = allocate_buffer (1024);

    /* Register a cleanup handler for this buffer, to deallocate it in case the thread exits or is cancelled. */

    pthread_cleanup_push (deallocate_buffer, temp_buffer);

    /* Do some work here that might call pthread_exit or might be cancelled... */

    /* Unregister the cleanup handler. Because we pass a nonzero value, this actually performs the cleanup by calling

deallocate_buffer. */

    pthread_cleanup_pop (1);

}

  • Thread Cleanup in C++
  • Use C++ destructors.
  • When the objects go out of scope because of an exception,
    C++ makes sure that destructors are called for those automatic variables.
  • If a thread calls pthread_exit, C++ doesn’t guarantee that
    destructors are called for all variables.
  • We can throw out an exception on the top level to let all variables
    out of scope and then in the exception handler, call pthread_exit.
  • Implementing Safe Thread Exit with C++ Exceptions

#include <pthread.h>

class ThreadExitException

{

public:

    /* Create an exception-signaling thread exit with RETURN_VALUE. */

    ThreadExitException (void* return_value) : thread_return_value_ (return_value) {}

    /* Actually exit the thread, using the return value provided in the constructor. */

    void* DoThreadExit ()

    {

        pthread_exit (thread_return_value_);

    }

private:

    /* The return value that will be used when exiting the thread. */

    void* thread_return_value_;

};

void do_some_work ()

{

    while (1) {

        /* Do some useful things here... */

        if (should_exit_thread_immediately ())

             throw ThreadExitException (/* thread’s
return value = */ NULL);

    }

}

void* thread_function (void*)

{

    try {

        do_some_work ();

    }

    catch (ThreadExitException ex) {

        /* Some function indicated that we should exit the thread. */

        ex.DoThreadExit ();

    }

    return NULL;

}

 

////////////////////////////////////////////////////////////////////

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

 

class ThreadExitException

{

public:

       
ThreadExitException(void * return_value):
thread_return_value(return_value){}

       
void * DoThreadExit()

       
{

               
pthread_exit(thread_return_value);

       
}

 

private:

       
void * thread_return_value;

 

};

 

class example

{

public:

       
example(int size)

       
{

               
printf("allocating...");

                memory = malloc(size);

       
}

 

       
~example()

       
{

               
printf("deallocating...");

                free(memory);

       
}

 

private:

       
void *memory;

};

 

void do_some_work()

{

       
printf("do some work...");

       
example e(100);

 

       
throw ThreadExitException(NULL);

}

 

void * thread_function(void *)

{

       
try

       
{

                do_some_work();

       
}

       
catch(ThreadExitException ex)

       
{

                ex.DoThreadExit();

       
}

       
return NULL;

}

 

int main()

{

       
pthread_t thread_id;

       
pthread_create(&thread_id, NULL, &thread_function, NULL);

        pthread_join(thread_id, NULL);

}

 

4.4 Synchronization and Critical Sections

4.4.1. Mutexes

  • Mutex is short for MUTual EXclusion locks.
  • A mutex is a special lock that only one thread may lock at
    a time.
  • To create a mutex
  • Call pthread_mutex_init
  • The first argument is pthread_mutex_t
  • The second argument is a mutex attribute object, NULL for
    default attributes.

pthread_mutex_t mutex;

pthread_mutex_init (&mutex, NULL);

  • pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • call pthread_mutex_lock to lock a mutex.
  • call pthread_mutex_unlock to unlocks a mutex
  • Job Queue Thread Function, Protected by a Mutex

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <pthread.h>

 

struct job

{

       
struct job* next;

       
int value;

};

 

struct job* job_queue;

 

void process_job(struct job*);

 

pthread_mutex_t job_queue_mutex =
PTHREAD_MUTEX_INITIALIZER;

 

void * process_queue_function (void * arg)

{

       
while(1)

       
{

                struct job* next_job;

 

               
pthread_mutex_lock(&job_queue_mutex);

                if(job_queue == NULL)

                        next_job = NULL;

                else

                {

                        printf("begin
removing a job.../n");

                        next_job = job_queue;

                        job_queue =
job_queue->next;

                        printf("after
removing a job.../n");

                }

 

               
pthread_mutex_unlock(&job_queue_mutex);

 

                if(next_job == NULL)

                {

                        sleep(5);

         
              continue;

                }

 

                process_job(next_job);

 

                free(next_job);

       
}

       
return NULL;

}

 

void process_job(struct job* p)

{

       
printf("The value is : %d./n", p->value);

}

 

void enqueue_job(struct job* new_job)

{

       
pthread_mutex_lock(&job_queue_mutex);

       
printf("begin inserting a job.../n");

       
new_job->next = job_queue;

       
job_queue = new_job;

       
printf("after inserting a job.../n");

       
pthread_mutex_unlock(&job_queue_mutex);

}

 

void * insert_queue_function(void * arg)

{

       
int i = 0;

       
while(i < 20)

       
{

                sleep(1);

                printf("put the value:
%d./n", i);

                struct job* new_job = (struct
job*)malloc(sizeof(struct job));

                new_job->next = NULL;

                new_job->value = i;

 

                enqueue_job(new_job);

                i++;

       
}

}

 

int main()

{

       
pthread_t insert_thread, process_thread;

       
pthread_create(&insert_thread, NULL, &insert_queue_function,
NULL);

       
pthread_create(&process_thread, NULL, &process_queue_function,
NULL);

       
pthread_join(insert_thread, NULL);

       
pthread_join(process_thread, NULL);

}

 

  • Three kinds of mutexes exist:
  • fast mutex (the default kind): locking this kind of mutex
    twice will cause a dead lock.
  • recursive mutex: this kind of mutex is allowed to be locked
    many times, you can unlock the mutex the same times to release the mutex.
  • error-checking mutex: the second lock to the mutex will return
    the failure code EDEADLK.
  • Use mutex attribute object to create different kinds of
    mutexes.

pthread_mutexattr_t attr;

pthread_mutex_t mutex;

pthread_mutexattr_init (&attr);

pthread_mutexattr_setkind_np (&attr,
PTHREAD_MUTEX_ERRORCHECK_NP);

pthread_mutexattr_setkind_np (&attr, PTHREAD_MUTEX_RECURSIVE_NP);

pthread_mutex_init (&mutex, &attr);

pthread_mutexattr_destroy (&attr);

 

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

 

pthread_mutex_t mutex;

 

void * thread_function(void * arg)

{

        printf("try the mutex.../n");

       
pthread_mutex_lock(&mutex);

       
printf("get the mutex.../n");

       
pthread_mutex_unlock(&mutex);

       
printf("release the mutex.../n");

}

 

int main()

{

       
pthread_mutexattr_t attr;

       
pthread_mutex_t mutex;

       
pthread_t thread;

 

       
pthread_mutexattr_init(&attr);

       
pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);

       
pthread_mutex_init(&mutex, &attr);

       
pthread_mutexattr_destroy(&attr);

 

       
pthread_mutex_lock(&mutex);

       
printf("lock the first time.../n");

       
pthread_mutex_lock(&mutex);

       
printf("lock the second time.../n");

 

       
pthread_create(&thread, NULL, &thread_function, NULL);

 

       
pthread_mutex_unlock(&mutex);

       
printf("unlock the first time.../n");

       
sleep(5);

 

       
pthread_mutex_unlock(&mutex);

       
printf("unlock the second time.../n");

}

  • pthread_mutex_trylock can test whether a mutex is locked
    without actually blocking on it.
  • If you call pthread_mutex_trylock on an unlocked mutex,
    you will lock the mutex and return zero.
  • If the mutex is already locked, pthread_mutex_trylock will
    not block and return immediately with the error code EBUSY.

4.4.2. Semaphores

  • A semaphore is a counter that can be used to synchronize
    multiple threads.
  • GNU/Linux provides two kinds of semaphore implementations.
  • Here is the POSIX standard semaphore implementation for
    communicating among threads.
  • The other implementation is used for communication among
    processes.
  • Each semaphore has a counter value, which is a
    non-negative integer.
  • A semaphore supports two basic operations:
  • A wait operation decrements the value of the semaphore by
    1.
  • If the value is already zero, the operation blocks until
    the value of the semaphore becomes positive. When the semaphore’s value becomes
    positive, it is decremented by 1 and the wait operation returns.
  • A post operation increments the value of the semaphore by
    1.
  • If the semaphore was previously zero and other threads are
    blocked in a wait operation on that semaphore, one of those threads is
    unblocked and its wait operation completes
  • A semaphore is represented by a sem_t variable.
  • Initialize it using the sem_init function
  • The first parameter is a pointer to the sem_t variable.
  • The second parameter should be zero
  • The third parameter is the semaphore’s initial value.
  • Deallocate it with sem_destroy.
  • To wait on a semaphore, use sem_wait.
  • To post to a semaphore, use sem_post.
  • The nonblocking wait function is sem_trywait
  • To retrieve the current value of a semaphore, use sem_getvalue

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <pthread.h>

#include <semaphore.h>

 

struct job

{

       
struct job* next;

       
int value;

};

 

struct job* job_queue;

 

void process_job(struct job*);

 

pthread_mutex_t job_queue_mutex =
PTHREAD_MUTEX_INITIALIZER;

 

sem_t job_queue_count;

 

void initialize_job_queue()

{

       
job_queue = NULL;

       
sem_init(&job_queue_count, 0, 0);

}

 

void * process_queue_function (void * arg)

{

       
while(1)

       
{

       
        struct job* next_job;

 

                sem_wait(&job_queue_count);

 

               
pthread_mutex_lock(&job_queue_mutex);

                printf("begin removing a
job.../n");

                next_job = job_queue;

                job_queue = job_queue->next;

                printf("after removing a
job.../n");

               
pthread_mutex_unlock(&job_queue_mutex);

 

                process_job(next_job);

 

                free(next_job);

       
}

       
return NULL;

}

 

void process_job(struct job* p)

{

       
printf("The value is : %d./n", p->value);

}

 

void enqueue_job(struct job* new_job)

{

       
pthread_mutex_lock(&job_queue_mutex);

       
printf("begin inserting a job.../n");

       
new_job->next = job_queue;

       
job_queue = new_job;

        sem_post(&job_queue_count);

       
printf("after inserting a job.../n");

       
pthread_mutex_unlock(&job_queue_mutex);

}

 

void * insert_queue_function(void * arg)

{

       
int i = 0;

       
while(i < 20)

       
{

                sleep(1);

     
          printf("put the
value: %d./n", i);

                struct job* new_job = (struct
job*)malloc(sizeof(struct job));

                new_job->next = NULL;

                new_job->value = i;

 

                enqueue_job(new_job);

                i++;

       
}

}

 

int main()

{

       
pthread_t insert_thread, process_thread;

       
pthread_create(&insert_thread, NULL, &insert_queue_function,
NULL);

       
pthread_create(&process_thread, NULL, &process_queue_function,
NULL);

       
pthread_join(insert_thread, NULL);

       
pthread_join(process_thread, NULL);

}

4.4.3. Condition Variables

  • If thread A waits on a condition variable, it is blocked
    until some other thread, thread B, signals the same condition variable.
  • Thread A must wait on the condition variable before thread
    B signals it.
  • If thread B signals the condition variable before thread A
    waits on it, the signal is lost.
  • Each condition variable must be used in conjunction with a
    mutex to prevent the race condition between checking the flag value and signaling
    or waiting on the condition variable.
  • A condition variable is represented by an instance of
    pthread_cond_t.
  • pthread_cond_init initializes a condition variable.
  • pthread_cond_signal signals a condition variable.A single
    thread that is blocked on the condition variable will be unblocked.
  • pthread_cond_broadcast unblocks all threads that are
    blocked on the condition variable.
  • pthread_cond_wait blocks the calling thread until the
    condition variable is signaled.
  • The argument is a pointer to the pthread_cond_t
    instance.The second
  • argument is a pointer to the pthread_mutex_t mutex
    instance.
  • When pthread_cond_wait is called, the mutex must already
    be locked by the calling thread. That function atomically unlocks the mutex and
    blocks on the condition variable.When the condition variable is signaled and
    the calling thread unblocks, pthread_cond_wait automatically reacquires a lock
    on the mutex.
  • Control a Thread Using a Condition Variable

#include <pthread.h>

int thread_flag;

pthread_cond_t thread_flag_cv;

pthread_mutex_t thread_flag_mutex;

void initialize_flag ()

{

    /* Initialize the mutex and condition variable. */

    pthread_mutex_init (&thread_flag_mutex, NULL);

    pthread_cond_init (&thread_flag_cv, NULL);

    /* Initialize the flag value. */

    thread_flag = 0;

}

/* Calls do_work repeatedly while the
thread flag is set; blocks if the flag is clear. */

void* thread_function (void* thread_arg)

{

    /* Loop infinitely. */

    while (1) {

    /* Lock the mutex before accessing the flag value. */

        pthread_mutex_lock (&thread_flag_mutex);

        while (!thread_flag)

        /* The flag is clear. Wait for a signal on the condition variable, indicating that the flag value has changed. When the

signal arrives and this thread unblocks, loop and check the flag again. */

            pthread_cond_wait (&thread_flag_cv, &thread_flag_mutex);

        /* When we’ve gotten here, we know the flag must be set. Unlock the mutex. */

        pthread_mutex_unlock (&thread_flag_mutex);

        /* Do some work. */

       do_work ();

    }

    return NULL;

}

/* Sets the value of the thread flag to
FLAG_VALUE. */

void set_thread_flag (int flag_value)

{

    /* Lock the mutex before accessing the flag value. */

    pthread_mutex_lock (&thread_flag_mutex);

    /* Set the flag value, and then signal in case thread_function is blocked, waiting for the flag to become set. However,

thread_function can’t actually check the flag until the mutex is unlocked. */

    thread_flag = flag_value;

    pthread_cond_signal (&thread_flag_cv);

    /* Unlock the mutex. */

    pthread_mutex_unlock (&thread_flag_mutex);

}

  • A condition variable may also be used without a condition,
    simply as a mechanism for blocking a thread until another thread “wakes it up.”

4.5 GNU/Linux Thread Implementation

  • On GNU/Linux, threads are implemented as processes.

(thread-pid) Print Process IDs for
Threads (The test result of fedora is not like this.
)

#include <pthread.h>

#include <stdio.h>

#include &l

抱歉!评论已关闭.