I wrote a program to learn about thread-specific data on Linux (Linux 3.13.0-24-generic #46-Ubuntu), as following.
I try to print thread id in the destructor function passed to pthread_key_create(), but it seems only sub threads succeed to print, but the main thread didn't print that info.
My question is:
Does the destructor function called right before or after termination of a thread?
The reason why main thread didn't print the info, is it due to the main thread already destroyed?
tsd_test.c
// test of thread-specific data
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t tidKey;
static void destructor(void *buf) {
unsigned long *_tid = buf;
printf("destroy, tid: %lu\n", *_tid);
free(buf);
}
static void createKey(void) {
int s = pthread_key_create(&tidKey, destructor);
if(s != 0) {
printf("failed to create key\n");
exit(-1);
}
}
void *store_tid() {
int s;
unsigned long *buf;
// create key
s = pthread_once(&once, createKey);
if(s != 0) {
printf("failed to create key\n");
exit(-1);
}
buf = pthread_getspecific(tidKey);
if(buf == NULL) { // thread call this function for the first time,
buf = malloc(sizeof(unsigned long));
if(buf == NULL) {
printf("failed to allocate memory, %s\n", strerror(errno));
exit(-1);
}
// register buffer to specified key & current thread,
s = pthread_setspecific(tidKey, buf);
if(s != 0) {
printf("failed to setspecific\n");
exit(-1);
}
}
// store tid to buffer,
*buf = (unsigned long)pthread_self();
printf("set tid to: %lu\n", *buf);
return buf;
}
void tsd_test() {
unsigned long *tidp_a = store_tid();
printf("tid - before call another thread: %lu\n", *tidp_a);
int s;
pthread_t t2;
s = pthread_create(&t2, NULL, &store_tid, NULL);
if(s != 0) {
printf("failed to create thread\n");
exit(-1);
}
s = pthread_join(t2, NULL);
if(s != 0) {
printf("failed to join thread\n");
exit(-1);
}
printf("tid - after call another thread: %lu\n", *tidp_a);
}
int main(int argc, char *argv[]) {
tsd_test();
return 0;
}
Compile:
gcc -pthread tsd_test.c
Output:
set tid to: 3076318976
tid - before call another thread: 3076318976
set tid to: 3076315968
destroy, tid: 3076315968
tid - after call another thread: 3076318976
You can see that only the sub thread print "destroy", while the main thread didn't.
The thread destructor is called when the thread exits, not when the process dies i.e. when main() exits, the entire process dies. So destructor will not be called on that.
Call pthread_exit(NULL); either at the end of main() function or at the end tst() function (both are same really). Now, you will see the destructor being called.
Related
I'm using Linux to learn semaphore, trnna test the function sem_init. The code seems simple but the error is unexpected, don't know why. Here's the code and the errors is below the code.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include<unistd.h>
#include <stdlib.h>
#define NITER 1000000
int cnt = 0;
sem_t mutex;
sem_init(&mutex,0,1);
void * Count(void * a)
{
int i, tmp;
for(i = 0; i < NITER; i++)
{
sem_wait(&mutex);
tmp = cnt; /* copy the global cnt locally */
tmp = tmp+1; /* increment the local copy */
cnt = tmp; /* store the local value into the global cnt */
sem_post(&mutex);
}
}
int main(int argc, char * argv[])
{
pthread_t tid1, tid2;
if(pthread_create(&tid1, NULL, Count, NULL))
{
printf("\n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&tid2, NULL, Count, NULL))
{
printf("\n ERROR creating thread 2");
exit(1);
}
if(pthread_join(tid1, NULL)) /* wait for the thread 1 to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if(pthread_join(tid2, NULL)) /* wait for the thread 2 to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if (cnt < 2 * NITER)
printf("\n BOOM! cnt is [%d], should be %d\n", cnt, 2*NITER);
else
printf("\n OK! cnt is [%d]\n", cnt);
pthread_exit(NULL);
}
my english is bad, if anything is hard to understand please tell me and ill respond you as soon as possible!thx
You can declare variables outside the main and the other function which mean that the variable is global .
But to call the function sem_init(&mutex,0,1); you should do it from the main or from another function. In your case , you have to do it in the main.
After moving the sem_init inside the main it compile
nabil#DESKTOP-8ECTID4:~/stackoverflow$ gcc bad.c -o bad -lpthread
nabil#DESKTOP-8ECTID4:~/stackoverflow$
Code:
http://man7.org/tlpi/code/online/book/threads/strerror_tsd.c
static void /* Free thread-specific data buffer */
destructor(void *buf)
{
free(buf);
}
static void /* One-time key creation function */
createKey(void)
{
int s;
/* Allocate a unique thread-specific data key and save the address
of the destructor for thread-specific data buffers */
s = pthread_key_create(&strerrorKey, destructor);
if (s != 0)
errExitEN(s, "pthread_key_create");
}
char *
strerror(int err)
{
int s;
char *buf;
/* Make first caller allocate key for thread-specific data */
s = pthread_once(&once, createKey);
if (s != 0)
errExitEN(s, "pthread_once");
buf = pthread_getspecific(strerrorKey);
if (buf == NULL) { /* If first call from this thread, allocate
buffer for thread, and save its location */
buf = malloc(MAX_ERROR_LEN);
if (buf == NULL)
errExit("malloc");
s = pthread_setspecific(strerrorKey, buf);
if (s != 0)
errExitEN(s, "pthread_setspecific");
}
if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) {
snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err);
} else {
strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN - 1);
buf[MAX_ERROR_LEN - 1] = '\0'; /* Ensure null termination */
}
return buf;
}
http://man7.org/tlpi/code/online/dist/threads/strerror_test.c
static void *
threadFunc(void *arg)
{
char *str;
printf("Other thread about to call strerror()\n");
str = strerror(EPERM);
printf("Other thread: str (%p) = %s\n", str, str);
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t t;
int s;
char *str;
str = strerror(EINVAL);
printf("Main thread has called strerror()\n");
s = pthread_create(&t, NULL, threadFunc, NULL);
if (s != 0)
errExitEN(s, "pthread_create");
s = pthread_join(t, NULL);
if (s != 0)
errExitEN(s, "pthread_join");
/* If strerror() is not thread-safe, then the output of this printf() be
the same as that produced by the analogous printf() in threadFunc() */
printf("Main thread: str (%p) = %s\n", str, str);
exit(EXIT_SUCCESS);
}
Question:
int pthread_key_create(pthread_key_t *key, void (destructor)(void *));
The implementation of strerror uses thread-specific data. Upon termination of a thread that has a non-NULL value associated with key, the
destructor function is automatically invoked by the Pthreads API and given that
value as its argument. Based on my testing, the main thread calling to strerror will NOT trigger the destructor but the child thread will. I would like to know why?
Thank you
Here is a simplified example:
#include <pthread.h>
#include <stdio.h>
static pthread_key_t key;
void destroy(void *data)
{
fprintf(stderr, "==> %s on thread %lu with argument %p\n", __func__, pthread_self(), data);
}
void *target(void *data)
{
// comment out the following line and destroy will not be called from child thread
pthread_setspecific(key, target);
fprintf(stderr, "%s set key to %p on thread %lu\n", __func__, pthread_getspecific(key), pthread_self());
return NULL;
}
int main(int argc, char *argv[])
{
fprintf(stderr, "%s is on thread %lu\n", __func__, pthread_self());
pthread_key_create(&key, destroy);
pthread_setspecific(key, main);
fprintf(stderr, "%s set key to %p\n", __func__, pthread_getspecific(key));
pthread_t child;
pthread_create(&child, NULL, target, NULL);
fprintf(stderr, "main thread created thread %lu\n", child);
pthread_join(child, NULL);
fprintf(stderr, "main thread joined child\n");
// comment out the following line and destroy will not be called from main thread
pthread_exit(main);
return 0;
}
According to the man page for pthread_key_create
At thread exit, if a key value has a non-NULL destructor pointer, and the thread has a non-NULL value associated with that key, the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.
In both the question code and the simplified example, each thread has set the key to a non-NULL value, so it seems like the destructor should be called on each thread.
But the way the main thread exits by default, the key specific destructors are not called. See pthread_create man page and question 24521968. Calling pthread_exit() at the end of main will invoke the destructor.
In my producer and consumer problem, I use sem_open() to initialize the semaphores. How could I test if sem_open() works in a correct way?
The program can be compiled, but when I run the program it does not print anything. I test the program and found the problem maybe about sem_open(). I find if I comment the sem_open() in the program, the program will run correctly.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
pthread_t pro_thread, con_thread;
pthread_mutex_t mutex;
int counter = 0;
sem_t *empty, *full;
void print_buffer(int counter) {
for (int i = 0; i < counter; i ++)
{
printf("*");
}
printf("\n");
}
void* producer(void* var) {
int item;
while(1) {
item = rand() % 100 + 1;
sem_wait(empty);
pthread_mutex_lock(&mutex);
while (counter == BUFFER_SIZE)
; // waiting
if(counter < BUFFER_SIZE) {
buffer[counter] = item;
counter ++;
printf("Producer: ");
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(full);
}
}
void* consumer(void* var) {
int item;
while(1) {
sem_wait(full);
pthread_mutex_lock(&mutex);
while (counter == 0)
; // waiting
if(counter > 0) {
counter --;
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(empty);
}
}
int main(int argc, char *argv[]) {
pthread_mutex_init(&mutex, NULL);
empty = sem_open("/mysem", O_CREAT, 0644, BUFFER_SIZE);
full = sem_open("/mysem", O_CREAT, 0644, 0);
pthread_create(&pro_thread, NULL, producer, NULL);
pthread_create(&con_thread, NULL, consumer, NULL);
pthread_exit(NULL);
return 0;
}
As stated in the sem_open man page:
The semaphore is identified by name.
Since your code provides the same name value (/mysem) for both sem_open calls it results in referencing the same semaphore for both full and empty. That's clearly not what the logic of the program should be. Instead, open different semaphores for each. It's also best practice to check the return values of all function calls.
empty = sem_open("/empty_sem", O_CREAT, 0644, BUFFER_SIZE);
if (empty == SEM_FAILED) {
perror("Failed to open semphore for empty");
exit(-1);
}
full = sem_open("/full_sem", O_CREAT, 0644, 0);
if (full == SEM_FAILED) {
sem_close(empty);
perror("Failed to open semphore for full");
exit(-1);
}
Hi im trying to implement faster cat than the one provided.
My current implementation looks like this:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define BUF_SIZE 1024*1024*1024
char buffer[BUF_SIZE];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_var2 = PTHREAD_COND_INITIALIZER;
int readed = 0;
/*
Read characters from standard input and saves them to buffer
*/
void *consumer(void *data) {
int r;
while(1) {
//---------CRITICAL CODE--------------
//------------REGION------------------
pthread_mutex_lock(&mutex);
if (readed > 0)
{
pthread_cond_wait(&cond_var2, &mutex);
}
r = read(0, buffer, BUF_SIZE);
readed = r;
pthread_cond_signal(&cond_var);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (r == -1){
printf("Error reading\n");
}
else if (r == 0) {
pthread_exit(NULL);
}
}
}
/*
Print chars readed by consumer from standard input to standard output
*/
void *out_producer(void *data) {
int w;
while(1){
//---------CRITICAL CODE--------------
//-------------REGION-----------------
pthread_mutex_lock(&mutex);
if (readed == 0)
{
pthread_cond_wait(&cond_var, &mutex);
}
w = write(1, buffer, readed);
readed = 0;
pthread_cond_signal(&cond_var2);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (w == -1){
printf("Error writing\n");
}
else if (w == 0) {
pthread_exit(NULL);
}
}
}
What would you suggest to make it faster?
Any ideas?
I was thinking about the BUF_SIZE, what would you think would be optimal size of buffer?
Main just makes the threads:
int main() {
// Program RETURN value
int return_value = 0;
// in - INPUT thread
// out - OUTPUT thread
pthread_t in, out;
// Creating in thread - should read from standard input (0)
return_value = pthread_create(&in , NULL, consumer, NULL);
if (return_value != 0) {
printf("Error creating input thread exiting with code error: %d\n", return_value);
return return_value;
}
// Creating out thread - should write to standard output (1)
return_value = pthread_create(&out, NULL, out_producer, NULL);
if (return_value != 0) {
printf("Error creating output thread exiting with code error: %d\n", return_value);
return return_value;
}
return_value = pthread_join(in, NULL);
return_value = pthread_join(out, NULL);
return return_value;
}
How exactly is adding threads to cat going to make it faster? You can't just throw parallelism at any program and expect it to run faster.
Cat basically just transports every line of input (usually from a file) to output. Since it's important that the lines are in order, you have to use mutual exclusion to avoid racing.
The upper bound of the speed (the fastest that cat can run) in parallel cannot be higher than cat in serial, since every thread must perform the serial actions, along with the cost of synchronization.
here's my problem: my code should execute all the executable files (i.e. all the binaries and all the scripts) in the current directory, concurrently.
Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.h>
/* struct created for passing arguments at every thread */
struct thread_data {
long thread_id;
char *nome_file;
};
/* task of every thread */
void *work(void *thread_args) {
long tid;
char *name;
struct thread_data *my_data;
my_data = (struct thread_data *)thread_args;
tid = my_data -> thread_id;
name = my_data -> nome_file;
printf("thread number %ld get file %s\n", tid, name);
execl(name, name, (char *)0);
printf("execl failed\n");
pthread_exit(NULL);
}
int filter(const struct dirent *entry) {
/* Filter for scandir(): I consider only the regular files */
if(entry -> d_type == DT_REG)
return 1;
else
return 0;
}
int main() {
int n, rc;
long t;
struct dirent **namelist;
pthread_attr_t attr;
void *status;
/* Number of regular files in the current directory */
n = scandir(".", &namelist, filter, alphasort);
if(n < 0) {
perror("scandir()");
exit(EXIT_FAILURE);
}
/* How many threads? */
pthread_t thread[n];
/* Every thread will receive one instance of the struct thread_data */
struct thread_data thread_data_array[n];
/* With this, I'm sure my threads will be joinable */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(t=0; t<n; t++) {
printf("Main: creating thread %ld\n", t);
/* Filling the arguments in the struct */
thread_data_array[t].thread_id = t;
thread_data_array[t].nome_file = namelist[t] -> d_name;
rc = pthread_create(&thread[t], &attr, work, (void *)&thread_data_array[t]);
if(rc) {
printf("ERROR: pthread_create() is %d\n", rc);
exit(EXIT_FAILURE);
}
}
pthread_attr_destroy(&attr);
for(t=0; t<n; t++) {
rc = pthread_join(thread[t], &status);
if(rc) {
printf("ERROR: pthread_join() is %d\n", rc);
exit(EXIT_FAILURE);
}
printf("Main: join succeeded on thread %ld\n", t);
}
printf("Main: program finished. Quitting...\n");
pthread_exit(NULL);
}
My program successfully reads the regular files in the current dir, and every thread get one file per time, but when the first binary or script is executed, the program quits!
Here's an example of its execution...
Main: creating thread 0
Main: creating thread 1
Main: creating thread 2
Main: creating thread 3
Main: creating thread 4
Main: creating thread 5
Main: creating thread 6
thread number 0 get file slide.pdf
execl failed
thread number 1 get file hello.sh
Congrats, you executed this script, I'm hello.sh!
And then, he won't continue the execution with other files. Perhaps the error is in the execl return value in case of success...
All of the exec-family functions replace the current process (not thread) by the named executable when they succeed; the only way they return is on failure. You should be using either fork followed by execl, or preferably, posix_spawn.