#include <stdio.h> // for fprintf(), sprintf(), stderr,
// fopen(), fclose(), FILE, NULL
#include <pthread.h> // for pthread_t, pthread_create(), pthread_join(),
// pthread_key_t, pthread_key_create(), pthread_self(),
// pthread_getspecific(), pthread_setspecific()
// pthread.h includes bits/pthreadtypes.h, which defines:
// /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
// typedef unsigned long int pthread_t;
// typedef unsigned int pthread_key_t;
// The key used to associate a log file pointer with each thread:
static pthread_key_t thread_log_key;
void write_to_thread_log (const char *message); // write to log file
void close_thread_log (void * thread_log); // Close log file pointer
void * thread_function (void * args); // create log file, write log
int main() // thread-specific data
{
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);
for (i = 0; i < 5; i++) /* Create threads to do the work */
{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;
}
// 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[40];
FILE * thread_log;
/* Generate the filename for this thread's log file: */
sprintf (thread_log_filename, "thread-%lu.log",
(unsigned long) pthread_self());
/* Open the log file for writing: */
thread_log = fopen (thread_log_filename, "w");
fprintf(stderr, "Opening file \"%s\"\n", thread_log_filename);
// Store the file pointer in thread-specific data under thread_log_key:
pthread_setspecific (thread_log_key, (void *) thread_log);
write_to_thread_log ("Thread starting...");
/* Do work here... */
return NULL;
}
/*
gcc tsd.c -o tsd -lpthread
./tsd
Opening file "thread-140346443351808.log"
Opening file "thread-140346409780992.log"
Opening file "thread-140346434959104.log"
Opening file "thread-140346426566400.log"
Opening file "thread-140346418173696.log"
rm thread*.log // clean
*/
*********************************************************************************
*********************************************************************************
*********************************************************************************
*********************************************************************************
*********************************************************************************
#include <stdio.h> // for printf(), scanf(), fprintf(), stderr, NULL
#include <stddef.h> // for size_t
#include <malloc.h> // for malloc(), free()
#include <pthread.h> // for pthread_t, pthread_create(), pthread_join(),
// pthread_cleanup_push(), pthread_cleanup_pop(), pthread_testcancel(),
// pthread_cancel(), pthread_exit()
void * allocate_buffer (size_t size);
void deallocate_buffer (void* buffer);
void * do_some_work (void * unused);
int main()
{
pthread_t thread;
pthread_create (&thread, NULL, &do_some_work, NULL);
// pthread_cancel(thread); // "Type a word: Deallocating buffer"
pthread_join (thread, NULL);
return 0;
}
void * allocate_buffer (size_t size)
{
return malloc (size);
}
void deallocate_buffer (void* buffer)
{
fprintf(stderr, "Deallocating buffer\n");
free (buffer);
}
void * do_some_work (void * unused)
{
/* 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);
// pthread_cleanup_push(free, temp_buffer); // no "Deallocating buffer"
/* Do some work here that might call pthread_exit() or might be
cancelled... */
pthread_testcancel(); // cancelation points
printf("Type a word: ");
scanf("%s", (char *)temp_buffer);
printf("You typed: %s\n", (char *)temp_buffer);
// pthread_exit(NULL); // deallocate_buffer() is still called
/* Unregister the cleanup handler. Because we pass a nonzero value,
this actually performs the cleanup by calling deallocate_buffer(). */
pthread_cleanup_pop(1); // push and pop must be in the same scope
return NULL;
}
/*
gcc cleanup.c -o cleanup -lpthread
./cleanup
Type a word: Hello!
You typed: Hello!
Deallocating buffer
*/
pthread_cleanup_push() and pthread_cleanup_pop() are implemented as macros and must be present in the same scope, meaning within the same brace (block) nesting level.
*********************************************************************************
*********************************************************************************
*********************************************************************************
*********************************************************************************
*********************************************************************************
#include <cstdio> // for printf()
#include <cstring> // for strcpy()
#include <malloc.h> // for malloc(), free()
#include <pthread.h> // for pthread_t, pthread_create(), pthread_join(),
// pthread_testcancel(), pthread_exit()
void * thread_function (void * unused);
int main()
{
pthread_t thread;
void *vp = NULL;
pthread_create (&thread, NULL, &thread_function, NULL);
pthread_join (thread, &vp);
if (vp != NULL)
{
printf("main(): %s\n", (char*)vp);
free(vp);
}
return 0;
}
class ThreadExitException
{
public:
/* Create an exception-signaling thread exit with `return_value': */
ThreadExitException (void * return_value)
: thread_return_value_ (return_value)
{printf("ThreadExitException(): %s\n", (char*)thread_return_value_);}
/* Actually exit the thread, using the return value provided
in the constructor: */
void * DoThreadExit(void)
{
printf("DoThreadExit(): %s\n", (char*)thread_return_value_);
pthread_exit (thread_return_value_);
return thread_return_value_;
}
private:
/* The return value that will be used when exiting the thread: */
void * thread_return_value_;
};
int should_exit_thread_immediately(void)
{
pthread_testcancel(); // cancelation point
return 1;
}
void do_some_work(void)
{
while (1)
{
/* Do some useful things here... */
void * return_value = malloc(1024);
strcpy((char*)return_value, "Goodbye!");
printf("do_some_work(): %s\n", (char*)return_value);
if (should_exit_thread_immediately())
{
throw ThreadExitException (return_value);
// throw ThreadExitException (/* thread's return value = */ NULL);
}
}
}
void * thread_function (void * unused)
{
try
{do_some_work();}
catch (ThreadExitException ex)
{
/* Some function indicated that we should exit the thread. */
return ex.DoThreadExit();
}
return NULL;
}
/*
g++ cxx-exit.cpp -o cxx-exit -lpthread
./cxx-exit
do_some_work(): Goodbye!
ThreadExitException(): Goodbye!
DoThreadExit(): Goodbye!
main(): Goodbye!
*/