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.
Related
I have a producer consumer program that reads a file char by char and puts the content inside a buffer.
I need help with outputting the number of rounds the producer function made to deliver characters to the buffer. A round would mean one or more continuous writes to the buffer without being interrupted by wait (due to a full queue).
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
/*
This program provides a possible solution for producer-consumer problem using mutex and semaphore.
I have used 5 producers and 5 consumers to demonstrate the solution. You can always play with these values.
*/
#define MaxItems 5 // Maximum items a producer can produce or a consumer can consume
#define BufferSize 5 // Size of the buffer
sem_t empty;
sem_t full;
int in = 0;
int out = 0;
int buffer[BufferSize];
pthread_mutex_t mutex;
void *producer(void *pno)
{
int item;
for(int i = 0; i < MaxItems; i++) {
item = rand(); // Produce an random item
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = item;
printf("Producer %d: Insert Item %d at %d\n", *((int *)pno),buffer[in],in);
in = (in+1)%BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
void *consumer(void *cno)
{
for(int i = 0; i < MaxItems; i++) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
int item = buffer[out];
printf("Consumer %d: Remove Item %d from %d\n",*((int *)cno),item, out);
out = (out+1)%BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
}
int main()
{
pthread_t pro[5],con[5];
pthread_mutex_init(&mutex, NULL);
sem_init(&empty,0,BufferSize);
sem_init(&full,0,0);
FILE *fp = fopen("file.txt", "r");
if (fp != NULL) {
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
p1.BUFFER_SIZE = ftell(fp);
if (p1.BUFFER_SIZE == -1) { /* Error */ }
/* Allocate our buffer to that size. */
p1.item = malloc(sizeof(char) * (p1.BUFFER_SIZE + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(p1.item, sizeof(char), p1.BUFFER_SIZE, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
p1.item[newLen++] = '\0'; /* Just to be safe. */
}
}
int a[5] = {1,2,3,4,5}; //Just used for numbering the producer and consumer
for(int i = 0; i < 5; i++) {
pthread_create(&pro[i], NULL, (void *)producer, (void *)&a[i]);
}
for(int i = 0; i < 5; i++) {
pthread_create(&con[i], NULL, (void *)consumer, (void *)&a[i]);
}
for(int i = 0; i < 5; i++) {
pthread_join(pro[i], NULL);
}
for(int i = 0; i < 5; i++) {
pthread_join(con[i], NULL);
}
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
In general, there is no way to determine whether the time it takes for a call to sem_wait() to return is extended on account of the semaphore's value initially being zero. The sem_wait() function does not communicate that information.
One thing you could do, however, is to start out with a sem_trywait(), which will fail instead of blocking if it cannot immediately decrement the target semaphore. You could increment a counter in that case, and then proceed to perform a regular sem_wait(). Example:
int full_count = 0;
void *producer(void *pno) {
int my_num = *(int *)pno;
for(int i = 0; i < MaxItems; i++) {
int item = rand(); // Produce an random item
int result = sem_trywait(&empty);
if (result == -1) {
if (errno == EAGAIN) {
full_count += 1;
result = sem_wait(&empty);
// handle any error ...
} else {
// handle other error ...
}
}
pthread_mutex_lock(&mutex);
buffer[in] = item;
printf("Producer %d: Insert Item %d at %d\n", my_num, buffer[in], in);
in = (in + 1) % BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
Do note that there is no guarantee there that in the event that sem_wait() is called, it will actually block, because the semaphore can be incremented between the trywait and the wait. But it does tell you that if a wait had been performed instead of the trywait, then that wait would have blocked. In that case the producer is indeed delayed on account of a full buffer, even if it doesn't spend any of that delay blocked in sem_wait().
I am learning how to use threads in C and have run into a problem when creating the threads. I am making a program that takes in 2 or more file names as command line arguments, counts the number of bytes in each file in their own thread, and then outputs the name of the largest file. When I use pthread_join() directly after creating a thread, the program runs as intended. However, I know this isn't how threads should be used because it defeats the purpose. When I use pthread_join() in a for loop after creating all the threads, then the program does not work correctly. Could anyone tell me what I am doing wrong? All help is appreciated. Here is my main function.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //mutex for changing max_bytes and max_name
int max_bytes = 0;
char max_name[100];
struct arg_struct{ //struct to hold args to pass the threads
int fd;
char name[100];
};
int main(int argc, char* argv[])
{
if(argc < 3){ //checks for correct number of arguments passed
perror("Wrong number of arguments");
return EXIT_FAILURE;
}
int arg_num = argc - 1; //holds number of arguments passed
pthread_t threadid[arg_num]; //array of thread IDs
struct arg_struct args;
for(int i = 0; i < arg_num; i++){
args.fd = open(argv[i+1], O_RDONLY);
memcpy(args.name, argv[i+1], sizeof(args.name)); //copies file name into arg_struct
int thread_err = pthread_create(&threadid[i], NULL, count_bytes, (void*)&args); //create thread by calling count_bytes and passing it a struct of args
//pthread_join(threadid[i], NULL);
if(thread_err != 0){
perror("pthread_create failed");
return EXIT_FAILURE;
}
}
for(int i = 0; i < arg_num; i++){
pthread_join(threadid[i], NULL);
}
printf("%s is the largest of the submitted files\n", max_name);
return 0;
}
This is the function that the threads are running.
void *count_bytes(void* arguments)
{
struct arg_struct *args = (struct arg_struct*)arguments; //casting arguments back to struct from void*
int fd = args -> fd;
char name[100];
memcpy(name, args -> name, sizeof(name)); //copies file name into name from args.name
int bytes = 0;
int size = 10;
char* buffer = (char*) malloc(size);
if(buffer == NULL){
perror("malloc failed");
exit(EXIT_FAILURE);
}
int buffer_count = 0;
for(int i = 0; i < size; i++){
buffer[i] = '\0'; //sets all elements to '\0' to determine end of file later
}
int read_return = read(fd, &buffer[buffer_count], 1);
if(read_return == -1){
perror("reading failed");
exit(EXIT_FAILURE);
}
while(buffer[buffer_count] != '\0'){
bytes++;
buffer_count++;
buffer[buffer_count] = '\0'; //sets previous element to '\0' to determine end of file later
if(buffer_count >= size){
buffer_count = 0; //buffer will hold up to 10 elements and then go back to the beginning
}
read_return = read(fd, &buffer[buffer_count], 1);
if(read_return == -1){
perror("reading failed");
exit(EXIT_FAILURE);
}
}
printf("%s has %d bytes\n", name, bytes);
pthread_mutex_lock(&mutex);
if(bytes > max_bytes){
max_bytes = bytes;
memcpy(max_name, name, sizeof(max_name));
}
//locks mutex to avoid race condition
//then sets bytes to max_bytes if it is later than max_bytes
//then locks mutex to allow another thread to have access
pthread_mutex_unlock(&mutex);
return NULL;
}
If it is of any use, these are the two outputs produced when it is running correctly
./a.out another buffered_readword.c
another has 8 bytes
buffered_readword.c has 3747 bytes
buffered_readword.c is the largest of the submitted files
And not correctly
./a.out another buffered_readword.c
buffered_readword.c has 1867 bytes
buffered_readword.c has 1881 bytes
buffered_readword.c is the largest of the submitted files
The problem is that there is only one args structure. After pthread_create is called the new thread may not run immediately. By the time the threads run it is likely that they will both see the same args values. Calling pthread_join inside the thread creation loop "fixes" that because it ensures each thread finishes before args is updated to the next value.
To fix properly pass a different args to each thread. Illustrative code to do that:
struct arg_struct args[arg_num];
for(int i = 0; i < arg_num; i++){
args[i].fd = open(argv[i+1], O_RDONLY);
memcpy(args[i].name, argv[i+1], sizeof(args[i].name));
int thread_err = pthread_create(&threadid[i], NULL, count_bytes, &args[i]);
....
This is for an Operating Systems programming assignment. I'm attempting to read n number of files, use threads to search each file for a number of occurrences for a specific character.
./mycount j new.txt some.txt here.txt hello.txt
The output for my test code as is should be:
argumentCount: 6
threadCount: 4
pthread_create() for thread 0 returns: 0
Thread 1
pthread_create() for thread 1 returns: 0
Thread 2
pthread_create() for thread 2 returns: 0
Thread 3
pthread_create() for thread 3 returns: 0
Thread 4
However each execution of mycount is different, with the last thread usually not executing/printing. Either that or they'll print sporadically, in tandem, etc.
I'm attempting to utilize a mutex to ensure the integrity of my data but I'm not sure what's really happening behind the scenes.
How do I ensure that everything finishes the same way each time? The last thread always returns 0, but it sometimes won't execute the function I give it completely.
Code:
//GLOBALS
int occurrences = 0;
//PROTOTYPES
void *scanFile( void *filePtr );
//Initialize space for mutex.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//Receive arguments from .exe call
void main ( int argumentCount, char *argumentVariables[] )
{
//Exit if argumentCount is > 50.
if (argumentCount > 50)
{
perror("Too many arguments. Enter less than 50.\n");
exit(EXIT_FAILURE);
}
printf("argumentCount: %d \n", argumentCount);
//Instantiate variables.
//i - iterator
//*newCommand - Used to hold string value of first command entered.
//*newVector - Used to hold string of the rest of the commands. Is a vector.
int i;
char *searchCharacter;
char *newVector[argumentCount];
//Iterate through command line arguments and split them.
for (i = 0; i < argumentCount; i++)
{
searchCharacter = argumentVariables[1];
if (i < argumentCount - 1)
{
newVector[i] = argumentVariables[1 + i];
}
else
{
newVector[i] = NULL;
}
}
//Exit if newest command is NULL.
if (searchCharacter == NULL)
{
perror("No character entered!\n");
exit(EXIT_FAILURE);
}
int threads = argumentCount - 2;
printf("threadCount: %d \n", threads);
pthread_t * thread = malloc(sizeof(pthread_t)*threads);
for (int i = 0; i < threads; i++)
{
int ret;
char *message = "Thread";
ret = pthread_create(&thread[i], NULL, scanFile, (void*) message);
if (ret != 0)
{
printf("Error - pthread_create() return code: %d\n", ret);
exit(EXIT_FAILURE);
}
printf("pthread_create() for thread %d returns: %d\n", i, ret);
}
exit(EXIT_SUCCESS);
}
void *scanFile( void *filePtr )
{
pthread_mutex_lock( &mutex );
char *message;
message = (char *) filePtr;
occurrences += 1;
printf("%s %d\n", message, occurrences);
pthread_mutex_unlock( &mutex );
}
Found the solution thanks to user2864740 and Ken Thomases.
Added:
for (int j = 0; j < threads; j++)
{
//Join the threads so all the data is good to go.
pthread_join(thread[j], NULL);
}
Correction:
for (int i = 0; i < threads; i++)
{
request[i].file = argumentVariables[i + 2];
request[i].character = searchCharacter;
//Create the thread. Any output from the integer newThread is an error code.
newThread = pthread_create(&thread[i], NULL, *scanFile, &request[i]);
if (newThread != 0)
{
printf("Error - pthread_create() return code: %d\n", newThread);
exit(EXIT_FAILURE);
}
}
for (int j = 0; j < threads; j++)
{
//Join the threads so all the data is good to go.
pthread_join(thread[j], NULL);
}
I am trying to implement a code to practice synchronization, so might not be best design or approach but goal is as below
Main thread
Creates a payload of 100 integers and waits for any thread to be available
When it gets signal from a thread its available - it unlocks the payload for copying and proceeds to create another payload
Worker thread
on creation of it makes itself available for data processing and sends signal that its available
Tries to lock the data payload from main thread and copy it to local array
( observing bug here - not able to access data properly)
Turn off the sign of available
( unable to turn off available state to off)
Keep processing data through local copy
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#define WORKERS 2
#define ARRAY_ELEMENTS 100
#define MAX 1000
pthread_mutex_t mutex_bucket1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_signal = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_go = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_busy = PTHREAD_COND_INITIALIZER;
static int value = 0;
bool available = false;
void *worker_thread(void *pbucket)
{
sleep(5);
while(1)
{
unsigned int count = 0;
int local_array[ARRAY_ELEMENTS];
int *ptbucket = (int*)pbucket;
setbuf(stdout, NULL);
pthread_mutex_lock(&mutex_signal);
printf(" -------------- \n chainging state to available \n --------- ");
available = true;
printf(" -------------- \n from thread sending go signal \n --------- ");
pthread_cond_signal(&cond_go);
pthread_mutex_unlock(&mutex_signal);
pthread_mutex_lock(&mutex_bucket1);
printf(" -------------- \n data part locked in thread for copying \n --------- ");
while(count < ARRAY_ELEMENTS)
{
printf(" %d - \n", ptbucket[count]); /***incorrect values***/
local_array[count] = ptbucket[count];
count++;
}
pthread_mutex_unlock(&mutex_bucket1);
/*Never able to acquire mutex_signal and change state to not available*/ **BUG**
pthread_mutex_lock(&mutex_signal);
printf(" -------------- \n chainging state to not available \n --------- ");
available = false;
pthread_mutex_unlock(&mutex_signal);
count = 0;
while(count < ARRAY_ELEMENTS)
{
printf(" %d - \n", local_array[count]);
count++;
}
printf(" -------------- \n about to sleep for 5secs \n --------- ");
sleep(5);
}
}
int main(void)
{
pthread_t thread_id[WORKERS];
unsigned int* pbucket1 = (int*) malloc(sizeof(int) * ARRAY_ELEMENTS);
unsigned int* pbucket;
for(int i = 0; i < WORKERS - 1; i++)
{
pthread_create(&thread_id[i], NULL, worker_thread, (void *) pbucket);
}
for(int i = 0; i < MAX; i++)
{
unsigned int count = 0;
pbucket = pbucket1;
// Make the payload ready
pthread_mutex_lock(&mutex_bucket1);
printf(" -------------- creating data payload --------- \n");
while(count < ARRAY_ELEMENTS)
{
pbucket1[count] = i;
i++;
count++;
}
printf(" -------------- \n waiting for go signal \n --------- ");
while(!available)
{
pthread_cond_wait(&cond_go, &mutex_signal);
}
pthread_mutex_unlock(&mutex_bucket1);
/*I believe after we unlock variable "available" can be mutexed
again by other thread but seems thinking is flawed */
printf(" -------------- \n Main thread sleep for 3 seconds \n --------- ");
sleep(3);
}
for(int i = 0; i < WORKERS; i++)
{
pthread_join(thread_id[i], NULL);
}
return 0;
}
I think some of your idea is backwards; It shouldn't be the main context that is waiting, it should be the worker threads waiting for data ...
The job of the main thread should be to keep populating the payload and waking one thread at a time to process it.
So here's some scribbled code that is a little more sensible, I think:
/**
file: answer.c
compile: gcc -o answer answer.c -pthread
usage: answer [numThreads] [numElements]
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define STATE_WAIT 1
#define STATE_READY 2
void *routine(void*);
typedef struct _shared_t {
pthread_mutex_t m;
pthread_cond_t c;
unsigned char state;
int *payload;
size_t numElements;
pthread_t *threads;
size_t numThreads;
} shared_t;
static inline void shared_init(shared_t *shared, size_t numThreads, size_t numElements) {
memset(shared, 0, sizeof(shared_t));
pthread_mutex_init(&shared->m, NULL);
pthread_cond_init(&shared->c, NULL);
shared->state = STATE_WAIT;
shared->numThreads = numThreads;
shared->numElements = numElements;
{
int it = 0;
shared->threads = (pthread_t*) calloc(shared->numThreads, sizeof(pthread_t));
while (it < shared->numThreads) {
if (pthread_create(&shared->threads[it], NULL, routine, shared) != 0) {
break;
}
it++;
}
}
}
static inline void shared_populate(shared_t *shared) {
if (pthread_mutex_lock(&shared->m) != 0) {
return;
}
shared->payload = (int*) calloc(shared->numElements, sizeof(int));
{
int it = 0,
end = shared->numElements;
while (it < end) {
shared->payload[it] = rand();
it++;
}
}
shared->state = STATE_READY;
pthread_cond_signal(&shared->c);
pthread_mutex_unlock(&shared->m);
}
static inline void shared_cleanup(shared_t *shared) {
int it = 0,
end = shared->numThreads;
while (it < end) {
pthread_join(shared->threads[it], NULL);
}
pthread_mutex_destroy(&shared->m);
pthread_cond_destroy(&shared->c);
free(shared->threads);
}
void* routine(void *arg) {
shared_t *shared = (shared_t*) arg;
int *payload;
do {
if (pthread_mutex_lock(&shared->m) != 0) {
break;
}
while (shared->state == STATE_WAIT) {
pthread_cond_wait(&shared->c, &shared->m);
}
payload = shared->payload;
shared->state = STATE_WAIT;
pthread_mutex_unlock(&shared->m);
if (payload) {
int it = 0,
end = shared->numElements;
while (it < end) {
printf("Thread #%ld got payload %p(%d)=%d\n",
pthread_self(), payload, it, payload[it]);
it++;
}
free(payload);
}
} while(1);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
shared_t shared;
int numThreads = argc > 1 ? atoi(argv[1]) : 1;
int numElements = argc > 2 ? atoi(argv[2]) : 100;
shared_init(&shared, numThreads, numElements);
do {
shared_populate(&shared);
} while (1);
shared_cleanup(&shared);
return 0;
}
Obviously, the code above is not very tolerant of errors, and is not easy to shutdown cleanly ... it's illustration only.
Let's first look at main so that we know what the flow of the main program is going to be:
int main(int argc, char *argv[]) {
shared_t shared;
int numThreads = argc > 1 ? atoi(argv[1]) : 1;
int numElements = argc > 2 ? atoi(argv[2]) : 100;
shared_init(&shared, numThreads, numElements);
do {
shared_populate(&shared);
} while (1);
shared_cleanup(&shared);
return 0;
}
It keeps a shared_t on the stack:
typedef struct _shared_t {
pthread_mutex_t m;
pthread_cond_t c;
unsigned char state;
int *payload;
size_t numElements;
pthread_t *threads;
size_t numThreads;
} shared_t;
Mostly self explanatory, mutex, condition and state are required for synchronization.
First of all the shared_t must be initialized with mutex, condition, state and threads using the provided options:
static inline void shared_init(shared_t *shared, size_t numThreads, size_t numElements) {
memset(shared, 0, sizeof(shared_t));
pthread_mutex_init(&shared->m, NULL);
pthread_cond_init(&shared->c, NULL);
shared->state = STATE_WAIT;
shared->numThreads = numThreads;
shared->numElements = numElements;
{
int it = 0;
shared->threads = (pthread_t*) calloc(shared->numThreads, sizeof(pthread_t));
while (it < shared->numThreads) {
if (pthread_create(&shared->threads[it], NULL, routine, shared) != 0) {
break;
}
it++;
}
}
}
When the worker threads are created by this routine, they are forced into a waiting state.
The first call to shared_populate in the loop awakens the first thread after setting the payload to some random numbers:
static inline void shared_populate(shared_t *shared) {
if (pthread_mutex_lock(&shared->m) != 0) {
return;
}
shared->payload = (int*) calloc(shared->numElements, sizeof(int));
{
int it = 0,
end = shared->numElements;
while (it < end) {
shared->payload[it] = rand();
it++;
}
}
shared->state = STATE_READY;
pthread_cond_signal(&shared->c);
pthread_mutex_unlock(&shared->m);
}
Note the use of pthread_cond_signal over pthread_cond_broadcast, because we only want to wake the first thread.
void* routine(void *arg) {
shared_t *shared = (shared_t*) arg;
int *payload;
do {
if (pthread_mutex_lock(&shared->m) != 0) {
break;
}
while (shared->state == STATE_WAIT) {
pthread_cond_wait(&shared->c, &shared->m);
}
payload = shared->payload;
shared->state = STATE_WAIT;
pthread_mutex_unlock(&shared->m);
if (payload) {
int it = 0,
end = shared->numElements;
while (it < end) {
printf("Thread #%ld got payload %p(%d)=%d\n",
pthread_self(), payload, it, payload[it]);
it++;
}
free(payload);
}
} while(1);
pthread_exit(NULL);
}
So we wake up in routine at the call to pthread_cond_wait, the state has changed, so we break out of the loop, we save the pointer to the payload, reset the state to WAIT, and release the mutex.
At this point main can repopulate the payload and awaken the next thread, meanwhile the current worker thread can process, and then free the payload.
Some advice:
Always use as few mutex and condition variables as possible (KISS)
Research the atomic nature of condition variables
Always follow the basic rules regarding acquisition and release of mutex and signaling of condition variables:
If you locked it, unlock it.
Only ever wait for something: predicated wait loops are absolutely required, all the time.
If you can't reproduce what I done, then take the code and try to expand upon it; The first thing you need to do is be able to shutdown the process gracefully (enter shared_cleanup), maybe you need a variable sized payload, or some other requirement not mentioned in the original question.
Note about printf ... appending to a stream is not guaranteed to be atomic, it so happens that most of the time on *nix it is ... since we are just doing show and tell, we don't need to care about that ... ordinarily, do not rely on atomicity for any stream operations ...
assume creating 3 worker threads by pthread_create,
in these worker thread routine, each call a simple infinite loop function which do not have a return to do counting
how to make worker thread gain control after calling infinite loop function and save the context of infinite loop function for calling in worker thread again?
Let me rephrase to see if I understood the problem.
You have a master thread which spawns 3 worker threads which each do a long running (infinite) job.
At a certain point you want to interrupt processing, save the state of all threads to resume where they left off at a later time.
I think the best way of doing this is organize your threads work in transactionally bound chunks. When restarting, you check the last completed transaction, and go from there.
But since I suspect this to be a homework assignment in low level thread plumbing, may i suggest a shared boolean which is checked on every time you go through the loop to exit and store the state afterwards. Aternatively "kill" the thread and catch the exception and store the state. The last option is messy.
I think you should clarify your question.
If every worker thread calls an infinite loop then I suppose that your master thread would have to call pthread_cancel() on each of them. From what I gather this might require calls to other pthread_*() functions to set the "cancelability" of the target threads.
Of course this suggestion begs the question. The vastly preferable approach would be to prevent those infinite loops. Write your code so that it has exit conditions ... so that the work is bounded by some sort of input or has some sort of event handling.
want to do the effect of a threadpool, after calling infinite loop function, each worker thread can change other tasks(other infinite loop function) to run
for example 3 worker thread can run 4 tasks(infinite loop functions)
#ifndef JOB_CPP
#define JOB_CPP
#include "job.h"
#define NUM_OF_TASKS 4
#define NUM_OF_WORKERS 3
void (* job_queue[NUM_OF_TASKS])(void*);
void (* fp[NUM_OF_WORKERS])(void*); // original running job
int running_task[NUM_OF_WORKERS];
int idle[NUM_OF_TASKS];
int last_running_task[NUM_OF_WORKERS];
int no_of_tasks_running[NUM_OF_WORKERS];
my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
void func1(void *arg)
{
int count = 0;
int status;
while(true)
{
//if((count % 100) == 0)
//printf("func1 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func2(void *arg)
{
int count = 0;
int status;
while(true)
{
//printf("func2 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func3(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func3 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func4(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func4 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.done);
}
}
void jobinit()
{
for(int i=0; i<NUM_OF_TASKS; i++)
{
job_queue[i] = NULL;
idle[i] = 0;
}
for(int i=0; i<NUM_OF_WORKERS; i++)
{
fp[i] = NULL;
running_task[i] = 0;
last_running_task[i] = 0;
no_of_tasks_running[i] = 0;
}
jobadd(func1);
jobadd(func2);
jobadd(func3);
jobadd(func4);
jobrun();
}
void jobadd(void (*job)(void*))
{
for(int i=0; i<4; i++)
{
if(job_queue[i] == NULL)
{
job_queue[i] = job;
return;
}
}
}
void* workserver(void *arg);
void* workserver(void *arg)
{
int status, timedout;
struct timespec timeout;
status = pthread_mutex_lock(&data.mutex);
while(true)
{
timedout = 0;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 2;
sleep(1);
//void (* clean)(void*);
status = pthread_cond_timedwait(&data.cv, &data.mutex, &timeout);
if(status == ETIMEDOUT){
printf("worker wait timed out %d\n", (int)arg);
timedout = 1;
}else if(status != 0){
printf("worker wait failed %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
return NULL;
}
printf("workserver number: %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
printf("function run %d\n", (int)arg);
(* job_queue[(int)arg])(NULL);
printf("cond wait start %d\n", (int)arg);
status = pthread_cond_wait(&data.done, &data.mutex);
printf("cond wait end\n");
status = pthread_mutex_lock(&data.mutex);
}
}
void jobrun()
{
for(int i=0; i<3; i++) {idle[i] = 0;}
pthread_t r1_threadid[3];
for(int i=0; i<3; i++)
{
pthread_create(&r1_threadid[i], NULL, workserver, (void*)i);
}
int status;
struct timespec timeout;
timeout.tv_sec = time (NULL) + 2;
timeout.tv_nsec = 0;
while(true)
{
status = pthread_mutex_lock(&data.mutex);
while(data.value == 0)
{
status = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout);
}
if(data.value != 0)
{
//printf("condition was signaled\n");
data.value = 0;
}
status = pthread_mutex_unlock(&data.mutex);
if(status != 0)
printf("unlock mutex error");
}
}
#endif