reader-writer accessing multiple readers - c

I have a few problems I can't solve in implementing WRITER-READER problem in UNIX.
First one is that I have no idea, how can I modify the code to work like threads are always calling to enter reading room. For example, when a writer is in the reading room, readers are waiting to access the reading room. When writer is escaping the reading room and readers are entering the reading room, he still is waiting for his chance.
The second one is that I have no idea how to modify the code to allow a few readers to enter the reading room. In my code only one thread can be in the same time in the reading room.
The third one is, how to recognize if writer or reader is starving? Which one is starving in my code?
Here is the code:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define READERS 15
#define WRITERS 10
int bufferw = 0, bufferr = 0, counterw = WRITERS, counterr = READERS;
int i;
pthread_mutex_t mwrite, mread;
pthread_cond_t condw, condr;
pthread_t r[READERS], w[WRITERS];
void *writer(void *ptr) {
pthread_mutex_lock(&mwrite);
{
counterr = READERS;
counterw = WRITERS;
++bufferw;
for(i=0; i<READERS; i++) while(bufferr > 0) pthread_cond_wait(&condw, &r[i]);
printf("WRITER ENTERING!");
pthread_mutex_unlock(&mwrite);
bufferw--;
}
pthread_cond_signal(&condr);
pthread_exit(0);
}
void *reader(void *ptr) {
counterr = READERS;
counterw = WRITERS;
{
++bufferr;
for(i=0; i<WRITERS; i++) while(bufferw == 1) pthread_cond_wait(&condr, &w[i]);
printf("READER ENTERING!");
bufferr = 0;
}
pthread_cond_signal(&condw);
pthread_exit(0);
}
int main(int argc, char* argv[]) {
pthread_mutex_init(&mwrite, 0);
pthread_mutex_init(&mread, 0);
pthread_cond_init(&condw, 0);
pthread_cond_init(&condr, 0);
for(i=0; i<WRITERS; i++) pthread_create(&w[i], NULL, writer, NULL);
for(i=0; i<READERS; i++) pthread_create(&r[i], NULL, reader, NULL);
for(i=0; i<WRITERS; i++) pthread_join(w[i], NULL);
for(i=0; i<READERS; i++) pthread_join(r[i], NULL);
pthread_cond_destroy(&condw);
pthread_cond_destroy(&condr);
pthread_mutex_destroy(&mwrite);
pthread_mutex_destroy(&mread);
return 0;
}
Thanks in advance for your help!
EDIT:// How can I avoid race in this case?

you could use one mutex and two conditional variables to implement this.
reader( ) {
pthread_mutex_lock(&m);
while (!(writers == 0))
pthread_cond_wait(&readersQ, &m);
readers++;
pthread_mutex_unlock(&m);
/* actual read */
pthread_mutex_lock(&m);
if (--readers == 0)
pthread_cond_signal(&writersQ);
pthread_mutex_unlock(&m);
}
writer( ) {
pthread_mutex_lock(&m);
writers++;
while (!((readers == 0) && (active_writers == 0))) {
pthread_cond_wait(&writersQ, &m);
}
active_writers++;
pthread_mutex_unlock(&m);
/* actual write */
pthread_mutex_lock(&m);
writers--;
active_writers--;
if (writers > 0)
pthread_cond_signal(&writersQ);
else
pthread_cond_broadcast(&readersQ);
pthread_mutex_unlock(&m);
}
This implementation is unfair to the readers, which means if there is a writer writing, readers will never get a choice to read. This is because writing is more important than reading. If you don't think so, I can also provide a version which is unfair to writers.
The reader will get a choice to read only when writers are equal to zero. If there is a single writer, the writer will not be zero and the reader cannot read.
If there are multiple writers, the variable active_writers will make sure that only one writer could write at a time.
EDIT
below is the version starve writers. For the reader, it is the same code.
writer( ) {
pthread_mutex_lock(&m);
while(!((readers == 0) &&(writers == 0)))
pthread_cond_wait(&writersQ, &m);
writers++;
pthread_mutex_unlock(&m);
/* actual write */
pthread_mutex_lock(&m);
writers--;
pthread_cond_signal(&writersQ);
pthread_cond_broadcast(&readersQ);
pthread_mutex_unlock(&m);
}

Related

Noticing if all threads are at pthread_cond_wait

I'm currently playing around with the POSIX library and trying out conditional variables.
At the moment I'm using a queue to scheduele tasks, if there is a task one thread uses pthread_cond_signal to wake up a thread that is waiting at pthread_cond_wait.
However there might be a point where no new tasks are created, so every thread is waiting at pthread_cond_wait and the programm is stuck there.
Is there anyway for me noticing if all my threads are waiting at pthread_cond_wait? I've tried using a counter and a leave variable but I did not get it working.
My code looks simliar to this code here: https://code-vault.net/lesson/j62v2novkv:1609958966824
,except each thread is adding new tasks (in executeTask) instead of only the main method adding them.
EDIT:
Here is my version of the code from the website above (which is loading for me:/)
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define THREAD_NUM 4
typedef struct Task
{
int a, b;
} Task;
Task taskQueue[256];
int taskCount = 0;
// THIS VARIABLE IS ADDED
int moreTasks = 10;
pthread_mutex_t mutexQueue;
pthread_cond_t condQueue;
void executeTask(Task *task)
{
usleep(50000);
int result = task->a + task->b;
printf("The sum of %d and %d is %d\n", task->a, task->b, result);
// THIS PART IS ADDED
if (moreTasks > 0)
{
pthread_mutex_lock(&mutexQueue);
moreTasks--;
pthread_mutex_unlock(&mutexQueue);
Task t = {
.a = rand() % 100,
.b = rand() % 100};
submitTask(t);
}
}
void submitTask(Task task)
{
pthread_mutex_lock(&mutexQueue);
taskQueue[taskCount] = task;
taskCount++;
pthread_mutex_unlock(&mutexQueue);
pthread_cond_signal(&condQueue);
}
void *startThread(void *args)
{
while (1)
{
Task task;
pthread_mutex_lock(&mutexQueue);
while (taskCount == 0)
{
pthread_cond_wait(&condQueue, &mutexQueue);
}
task = taskQueue[0];
int i;
for (i = 0; i < taskCount - 1; i++)
{
taskQueue[i] = taskQueue[i + 1];
}
taskCount--;
pthread_mutex_unlock(&mutexQueue);
executeTask(&task);
}
}
int main(int argc, char *argv[])
{
pthread_t th[THREAD_NUM];
pthread_mutex_init(&mutexQueue, NULL);
pthread_cond_init(&condQueue, NULL);
int i;
for (i = 0; i < THREAD_NUM; i++)
{
if (pthread_create(&th[i], NULL, &startThread, NULL) != 0)
{
perror("Failed to create the thread");
}
}
srand(time(NULL));
for (i = 0; i < 100; i++)
{
Task t = {
.a = rand() % 100,
.b = rand() % 100};
submitTask(t);
}
for (i = 0; i < THREAD_NUM; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Failed to join the thread");
}
}
pthread_mutex_destroy(&mutexQueue);
pthread_cond_destroy(&condQueue);
return 0;
}
My Probleme now is that after a while the taskCount is always zero and tehrefore all my threads are at pthread_cond_wait(&condQueue, &mutexQueue); in the startThread methods.
Is ther any way of me noticing if all threads are at this place? As statet above if already tried using a counter for the threads that are currently waiting (and also a version where I counted the threads that are working) but I could not figure out how to stop all the threads once every task is done.
If you want to know how many threads are waiting on a condition var, just increase a global counter before you go into wait mode and decrease it on wake up. With that you'll know how many threads are currently waiting.
e.g.
//global scope
int num_waiting_threads = 0;
//in function startThread
while (taskCount == 0)
{
//if num_waiting_threads == THREAD_NUM, all threads are waiting
++num_waiting_threads;
pthread_cond_wait(&condQueue, &mutexQueue);
--num_waiting_threads;
}
Since you have a fixed number of tasks, after processing every task, every thread will be sooner or later just waiting around for newly submitted tasks. Your execute function will only add in total 10 new tasks (moreTasks is initialized with 10 and decreased continuously and if that counter hits zero, no more tasks will be submitted).
Therefore, you could/should use pthread_cond_timedwait and wake up by yourself to check the num_waiting_threads state. If all threads are waiting, break out of the loop and exit the thread.

Mutex and conditionals issue, problem with synchronization between threads

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
char mutual[100];
int firstWrote = 0;
int secondWrote = 0;
int firstFinished = 0;
int secondFinished = 0;
void* reader(void* arg)
{
FILE* file = fopen((const char*)arg,"r");
if(file == NULL)
{
printf("Problem with opening file %s",(const char*)arg);
exit(4);
}
else
{
char which[25];
while(fgets(mutual,100,file))
{
pthread_mutex_lock(&mutex);
strcpy(which,(const char*)arg);
if(strcmp(which,"/etc/profile")==0)
{
firstWrote = 1;
//printf("%s\n",mutual);
fflush(stdout);
}
if(strcmp(which,"/etc/passwd")==0)
{
secondWrote = 1;
//printf("%s\n",mutual);
fflush(stdout);
}
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
if(strcmp(which,"/etc/profile")==0)
{
firstWrote = 0;
firstFinished= 1;
}
else if(strcmp(which,"etc/passwd")==0)
{
secondWrote = 0;
secondFinished = 1;
}
}
fclose(file);
pthread_exit(NULL);
}
int main(void)
{
FILE* pawel1 = fopen("PAWEL1","w");
FILE* pawel2 = fopen("PAWEL2","w");
if(pawel1 == NULL || pawel2 == NULL)
{
printf("Problem with opening file");
return 1;
}
pthread_t p1,p2;
pthread_attr_t attr;
if(pthread_attr_init(&attr) != 0)
exit(2);
if(pthread_attr_setd2etachstate(&attr,PTHREAD_CREATE_DETACHED))
exit(3);
pthread_create(&p1,&attr,reader,(void*)"/etc/profile");
pthread_create(&p2,&attr,reader,(void*)"/etc/passwd");
while(1)
{
pthread_mutex_lock(&mutex);
if(firstFinished == 1 && secondFinished == 1)
break;
pthread_cond_wait(&cond,&mutex);
if(firstWrote == 1)
{
fprintf(pawel1,"%s",mutual);
firstWrote = 0;
}
if(secondWrote == 1)
{
fprintf(pawel2,"%s",mutual);
secondWrote = 0;
}
pthread_mutex_unlock(&mutex);
}
fclose(pawel1);
fclose(pawel2);
pthread_attr_destroy(&attr);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
The app task is to made two different thread read from two files (/etc/passwd and /etc/profile) to a global buffer, and print results to proper file (PAWEL1 or PAWEL2) in main function , and it seems that i handle this behaviour with global flags but what i get is all lines from passwd and profile in one file - PAWEL2, and the file PAWEL1 is left empty.
Since you share a one-line buffer among all threads, including both readers, you must ensure that the main thread runs after each reader thread, never one reader immediately after the other (or itself). Otherwise, one reader can overwrite the data and status flags set by the other. You can accomplish this by
using the existing state flags to determine whose turn it is to run, and
broadcasting to the CV instead of merely signalling it, so that all participating threads get an opportunity to evaluate whether it is appropriate for them to perform a unit of work.
In particular, the rules could look like this:
Readers can run if !firstWrote && !secondWrote, which shows that the buffer is available for new data. They set the appropriate one of those variables after successfully reading the line, thus blocking both readers from overwriting the buffer until its contents are consumed, or they set the appropriate Finished variable and terminate if they cannot read a line.
The main thread can run if firstWrote || secondWrote || (firstFinished && secondFinished). After successfully reading out the buffer, it is responsible for resetting the appropriate one of firstWrote and secondWrote to zero.
When I say a thread "can run", I am talking about the condition associated with each thread's CV wait. The proper idiom for CV usage always involves such a condition, and it looks like this (pseudocode):
lock_mutex()
// ... maybe other code ...
while (condition_is_false()) {
wait_on_cv()
}
// ... maybe other code ...
unlock_mutex()
All accesses to the data that contribute to the condition must be performed under protection from the mutex.
The loop around the wait accounts for two main things:
Control arriving at the condition check when the thread is already clear to proceed
Waking from the wait despite not being clear to proceed, either because of receiving a signal or spuriously (which occasionally does happen)
You can add another level of looping around that (and that would be appropriate for your uses).
Note also that you could simplify your logic considerably by using one set of *Wrote and *Finished variables instead of a separate set for each reader. You would then achieve the necessary distinction among program states by using more values for those variables than just 0 and 1.

How do you setup callback in reader/writer multi-threading program

I have written a reader/writer lock implementation and what I plan to do is to setup callback for each thread. Let's say we have 3 reader threads and 3 of them have read a value X. Now a writer thread updates the value X to X+100. This should send a callback to all the 3 reader threads that the value has changed. How do we implement such a callback in the multi-threading environment in C programming language?
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdint.h>
sem_t dbAccess;
sem_t readCountAccess;
int readCount=0;
void *Reader(void *arg);
void *Writer(void *arg);
int main(int argc, char* argv[])
{
int i=0, num_of_readers = 0, num_of_writers = 0;
//inititalizing semaphores
sem_init(&readCountAccess,0,1);
sem_init(&dbAccess,0,1);
pthread_t readers_tid[100], writer_tid[100];
num_of_readers = atoi(argv[1]);
num_of_writers = atoi(argv[2]);
for(i = 0; i < num_of_readers; i++)
{
pthread_create(&readers_tid[i], NULL , Reader, (void *) (intptr_t) i);
}
for(i = 0;i < num_of_writers; i++)
{
pthread_create(&writer_tid[i], NULL, Writer, (void *) (intptr_t) i);
}
for(i = 0; i < num_of_writers; i++)
{
pthread_join(writer_tid[i],NULL);
}
for(i = 0; i < num_of_readers; i++)
{
pthread_join(readers_tid[i], NULL);
}
sem_destroy(&dbAccess);
sem_destroy(&readCountAccess);
return 0;
}
void * Writer(void *arg)
{
sleep(1);
int temp=(intptr_t) arg;
printf("Writer %d is trying to enter into database for modifying the data\n",temp);
sem_wait(&dbAccess);
printf("Writer %d is writting into the database\n",temp);
printf("Writer %d is leaving the database\n");
sem_post(&dbAccess);
}
void *Reader(void *arg)
{
sleep(1);
int temp=(intptr_t) arg;
printf("Reader %d is trying to enter into the Database for reading the data\n",temp);
sem_wait(&readCountAccess);
readCount++;
if(readCount==1)
{
sem_wait(&dbAccess);
printf("Reader %d is reading the database\n",temp);
}
sem_post(&readCountAccess);
sem_wait(&readCountAccess);
readCount--;
if(readCount==0)
{
printf("Reader %d is leaving the database\n",temp);
sem_post(&dbAccess);
}
sem_post(&readCountAccess);
}
I can see 2 possible approaches:
1. Let the readers call a function when they'd like to be notified. The writer would have to mark something per-reader thread to say they have to call your CB on the shared variable. This would be my preferred approach, as I'd design readers to know when they need these updates.
2. Signal the readers to have them execute some code from a signal handler. You can use SIG_USR1/2 for that, and add some additional marking somewhere to know what changed and what to call. This is less clean, obviously, but I imagine would be more handy when these threads are created by 3rd party and you cannot control what they're doing.
HTH
EDIT
I forgot another important thing - if you're only updating a POD variable (int, etc) you may use the method 1 with a seqlock and a local copy per reader thread. This way every reader would know did the value change.
Another consideration is do you need readers to know only the last value or do they need to respond to every single change? if you need to respond to every change you can use a lock free queue, one per reader, and have the writer push into every one of them.

How to get two pthread threads to respond to each others' wait and signal conditions?

I'm having a bit of trouble getting a basic two-thread arrangement working.
I am reading a chunk of bytes into memory from stdin in one "producer" thread, and processing those bytes in a second "consumer" thread, once those bytes are available. Once the bytes are consumed, the consumer thread goes back to being dormant and the producer thread gets running again.
I am using pthread_cond_wait() and pthread_cond_signal() to have the two threads communicate to each other that data are produced or consumed.
Here is the code for the two threads:
void * produce_bytes(void *t_data)
{
pthread_data_t *d = (pthread_data_t *)t_data;
do {
pthread_mutex_lock(&d->input_lock);
d->n_bytes = fread(d->in_buf, sizeof(unsigned char), BUF_LENGTH_VALUE, stdin);
if (d->n_bytes > 0) {
fprintf(stdout, "PRODUCER ...signaling consumer...\n");
pthread_cond_signal(&d->input_cond);
fprintf(stdout, "PRODUCER ...consumer signaled...\n");
}
pthread_mutex_unlock(&d->input_lock);
} while (d->n_bytes > 0);
return NULL;
}
void * consume_bytes(void *t_data)
{
pthread_data_t *d = (pthread_data_t *)t_data;
pthread_mutex_lock(&d->input_lock);
while (d->n_bytes == 0)
pthread_cond_wait(&d->input_cond, &d->input_lock);
fprintf(stdout, "CONSUMER ...consuming chunk...\n");
d->n_bytes = 0;
fprintf(stdout, "CONSUMER ...chunk consumed...\n");
pthread_mutex_unlock(&d->input_lock);
}
The pthread_data_t is a struct I use to keep track of state:
typedef struct {
pthread_mutex_t input_lock;
pthread_cond_t input_cond;
unsigned char in_buf[BUF_LENGTH_VALUE];
size_t n_bytes;
} pthread_data_t;
I configure variables in my main() function; here is the relevant excerpt:
pthread_t producer_thread = NULL;
pthread_t consumer_thread = NULL;
pthread_data_t *thread_data = NULL;
thread_data = malloc(sizeof(pthread_data_t));
thread_data->n_bytes = 0;
pthread_mutex_init(&(thread_data->input_lock), NULL);
pthread_cond_init(&(thread_data->input_cond), NULL);
pthread_create(&producer_thread, NULL, produce_bytes, (void *) thread_data);
pthread_create(&consumer_thread, NULL, consume_bytes, (void *) thread_data);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
When I run this, produce_bytes() signals consume_bytes() successfully on the first iteration, but on the second and subsequent iterations, a signal is sent to consume_bytes() and it never gets heard, so the consumer function never gets run again:
PRODUCER ...signaling consumer...
PRODUCER ...consumer signaled...
CONSUMER ...consuming chunk...
CONSUMER ...chunk consumed...
PRODUCER ...signaling consumer...
PRODUCER ...consumer signaled...
PRODUCER ...signaling consumer...
PRODUCER ...consumer signaled...
PRODUCER ...signaling consumer...
PRODUCER ...consumer signaled...
...
I am using the tutorial here as the basis for what I'm trying to do. What I am doing wrong?
There are a few issues with that code:
produce_bytes locks the mutex for the duration of the blocking call to fread. A general rule of thumb for responsive applications is to lock the mutex for as short periods as possible. You may like to read the input into a temporary buffer first, then lock the mutex and copy the data to the buffer shared between threads. Same applies to consume_bytes which holds the mutex while calling fprintf which can block.
produce_bytes in while(d->n_bytes > 0) does not hold the mutex, which is a race condition because consume_bytes assigns a new value to d->n_bytes. Assuming you would like to exit that loop when fread returns 0 (EOF), you need to copy the return value of fread into a local variable not shared between threads and use that as the condition in while(read_bytes > 0)
consume_bytes does not have any loop around it so that it returns after the first condition variable notification. You probably would like to wrap it into a while loop and exit only when EOF (0 bytes) have been read.
Here is a working example which addresses Maxim's point 2 and 3, but not 1 because that is necessary for responsiveness but not strictly for correctness.
Note that I have not implemented a means for the producer to signal EOF to the consumer, so the consumer will never exit.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_LENGTH_VALUE 100
typedef struct {
pthread_mutex_t input_lock;
pthread_cond_t input_cond;
unsigned char in_buf[BUF_LENGTH_VALUE];
size_t n_bytes;
} pthread_data_t;
void * produce_bytes(void *t_data)
{
pthread_data_t *d = (pthread_data_t *)t_data;
size_t local_byte_count = 0;
do {
pthread_mutex_lock(&d->input_lock);
local_byte_count = fread(d->in_buf, sizeof(unsigned char),
BUF_LENGTH_VALUE, stdin);
d->n_bytes += local_byte_count;
if (d->n_bytes > 0) {
fprintf(stdout, "PRODUCER ...signaling consumer...\n");
pthread_cond_signal(&d->input_cond);
fprintf(stdout, "PRODUCER ...consumer signaled...\n");
}
pthread_mutex_unlock(&d->input_lock);
// This is added to slow down the producer so that we can observe
// multiple consumptions.
sleep(1);
} while (local_byte_count > 0);
return NULL;
}
void * consume_bytes(void *t_data)
{
pthread_data_t *d = (pthread_data_t *)t_data;
while (1) {
pthread_mutex_lock(&d->input_lock);
while (d->n_bytes == 0) {
fprintf(stdout, "CONSUMER entering wait \n");
pthread_cond_wait(&d->input_cond, &d->input_lock);
}
fprintf(stdout, "CONSUMER ...consuming chunk...\n");
d->n_bytes = 0;
fprintf(stdout, "CONSUMER ...chunk consumed...\n");
pthread_mutex_unlock(&d->input_lock);
fflush(stdout);
}
}
int main(){
pthread_t producer_thread = NULL;
pthread_t consumer_thread = NULL;
pthread_data_t *thread_data = NULL;
thread_data = malloc(sizeof(pthread_data_t));
thread_data->n_bytes = 0;
pthread_mutex_init(&(thread_data->input_lock), NULL);
pthread_cond_init(&(thread_data->input_cond), NULL);
pthread_create(&producer_thread, NULL, produce_bytes, (void *) thread_data);
pthread_create(&consumer_thread, NULL, consume_bytes, (void *) thread_data);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
}

threads have the same id

I learn threads. I have read that thread terminates after it is out of a function (that is passed as parameter to pthread_create function).
So I create threads in the loop, they are executed and afterwards they are terminated.
(sorry for some long code)
But when I call a function pthread_create, new threads get the same ids. Why?
struct data {
FILE *f;
};
void *read_line_of_file(void *gdata) {
pthread_mutex_lock(&g_count_mutex); // only one thread can work with file,
//doing so we block other threads from accessing it
data *ldata = (data *) gdata;
char line[80];
int ret_val =fscanf(ldata->f,"%s",line);
pthread_mutex_unlock(&g_count_mutex); // allow other threads to access it
if (ret_val != EOF)
printf("%s %lu\n ", line, pthread_self());
// some time consuming operations, while they are being executed by one thread,
// other threads are not influenced by it (if there are executed on different cores)
volatile int a=8;
for (int i=0;i <10000;i++ )
for (int i=0;i <10000;i++ ) {
a=a/7+i;
}
if (ret_val == EOF) // here thread ends
pthread_exit((void *)1);
pthread_exit((void *)0);
}
int main() {
int kNumber_of_threads=3, val=0;
pthread_t threads[kNumber_of_threads];
int ret_val_from_thread=0;
data mydata;
mydata.f = fopen("data.txt","r");
if ( mydata.f == NULL) {
printf("file is not found\n");
return 0;
}
for( ; val != 1 ;) {
// THIS IS THAT PLACE, IDs are the same (according to the number of processes),
// I expected them to be changing..
for(int i=0; i<kNumber_of_threads; i++) {
pthread_create(&threads[i],NULL,read_line_of_file, &mydata);
}
for(int i=0; i<kNumber_of_threads; i++) {
pthread_join(threads[i], (void **) &ret_val_from_thread);
if (ret_val_from_thread != 0)
val = ret_val_from_thread;
}
printf(" next %d\n",val);
}
printf("work is finished\n");
fclose(mydata.f);
return 0;
}
as result, I see that id of threads are not being changed:
I wonder, are new threads really created?
Thanks in advance!
Thread IDs are only guaranteed to be different among currently running threads. If you destroy a thread and create a new one, it may well be created with a previously used thread ID.

Resources