I am using Glib to develop a multi-threading C software.
I would like to have a set of alive threads. Once some thread finishes, another thread starts with a different parameter. It is something like a thread pool.
I am using glib thread to implement the multi-threading. But I cannot find a lot of tutorials from Google. I can now start a set of threads, but have no idea about the waiting. Some code of mine:
GThread *threads[n_threads];
thread_aux_t *data = (thread_aux_t*) calloc(n_threads, sizeof(thread_aux_t));
for (i = 0; i < n_threads; ++i) {
data[i].parameter = i;
threads[i] = g_thread_create((GThreadFunc) pe_lib_thread, data + i,
TRUE, NULL);
}
/* wait for threads to finish */
for (i = 0; i < n_threads; ++i) {
g_thread_join(threads[i]); // How to start a new thread depending on the return value?
}
free(data);
Thanks.
Problem solved. Update:
Just found a thread pool implementation of glib: Thread Pools. I have run it and it works correctly.
The code is written as:
// 'query' is for this new thread,
// 'data' is the global parameters set when initiating the pool
void *pe_lib_thread(gpointer query, gpointer data) {
}
void run_threads() {
GThreadPool *thread_pool = NULL;
// Global parameters by all threads.
thread_aux_t *data = (thread_aux_t*) calloc(1, sizeof(thread_aux_t));
data->shared_hash_table = get_hash_table();
g_thread_init(NULL);
thread_pool = g_thread_pool_new((GFunc) pe_lib_thread, data, n_threads,
TRUE, NULL);
// If n_threads is 10, there are maximum 10 threads running, others are waiting.
for (i = 0; i < n_queries; i++) {
query = &queries[i];
g_thread_pool_push(thread_pool, (gpointer) query, NULL);
}
g_thread_pool_free(thread_pool, 0, 1);
}
g_thread_join returns the return value, so you just check it.
Let's say you want to create a new process if the return value is 17.
for (i = 0; i < n_threads; ++i) {
if (threads[i] && g_thread_join(threads[i]) == 17) {
/* Start a new thread. */
threads[i] = g_thread_create((GThreadFunc) pe_lib_thread, data + i,
TRUE, NULL);
} else {
threads[i] = NULL;
}
}
Related
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.
I am making a raytracer, im trying to use pthread to divide the rendering. i noticed that isnt helping with the speed because the function pthread_join is to slow, if i use a loop to make the 'await' is way faster and works almost every time fine. But i cant use that because the time of rendering changes with the scene.
Is there a way to check if a thread is finished, on a more efficient way. This is the code.
`
int threats(t_file *c) //this function creates the threads
{
int i;
int err;
pthread_t th[THREADS];
i = 0;
printf("1\n");
c->thread = -1;
mlx_clear_window(c->mlx_ptr, c->win_ptr);
while (i < THREADS)
{
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)c);
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
// while (i-- >= 0)
// pthread_join(th[i], 0);
//my await function xd
while (i < 200000000)
i++;
mlx_put_image_to_window(c->mlx_ptr, c->win_ptr, c->img.mlx_img, 0, 0);
c->thread = 0;
return 1;
}
void paint_scene(void *a)
{
int y;
int x;
t_ray ray;
int color;
t_file *c;
c = (t_file *)a;
color = 0;
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
x = 0;
while (x < c->win_width)
{
ray = generate_ray(x, y, *c);
color = get_intersections(&ray, c);
if (c->ligth)
color = shading(&ray, color, c);
my_mlx_pixel_put(&c->img, x, y, color);
x++;
}
//ft_printf("\rLoading%d: %d%%", c->thread, y / (c->win_heigth / 100));
y++;
}
pthread_exit(0);
}
`
You have a concurrency problem here in your thread function:
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
....
}
c->thread is shared between all threads, and based on likely thread timings and current face of the moon, I can make an educated guess and say that the first thread is calculating the whole image. When starting up, the first thread might see c->thread == -1, but later (if thread startup is faster than the while loop) other thread increase the value until the first thread sees c->thread == THREADS-1
To fix this, each call to create_thread must pass a pointer to a unique parameter object that holds that threads id. So remove the thread member from t_file. It probably serves no purpose there. And create a type of struct that holds the parameters to the thread function:
struct thread_param
{
unsigned int thread;
file_t *c;
}
You use it like this when starting threads:
struct thread_param params[THREADS];
while (i < THREADS)
{
params[i].thread = i;
params[i].c = c;
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)&(params[i]));
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
And you access the data in your thread function:
void paint_scene(void *a)
{
struct thread_param *param = (struct thread_param *)a;
unsigned int thread = param->thread;
t_file *c = param->c;
/*
in the rest of the code you remove `c->thread++`
and replace `c->thread` with `thread`
*/
....
}
If you have atomic data types (C11, #ifndef __STDC_NO_ATOMICS__) then implement a global counter and wait until it hits zero (if decreasing) or the amount of threads (if increasing).
e.g.
#include <stdatomic.h>
atomic_int num_jobs;
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
--num_jobs;
pthread_exit(0);
}
int main()
{
num_jobs = THREADS; // same as your number of threads
create_threads(THREADS); // number of threads = THREADS
while (num_jobs) { // loop while threads running
//sleep for a while
}
join_threads(); // join threads for cleanup
return 0;
}
Otherwise classic lock mechanics,
e.g.
#include <pthread.h>
pthread_spinlock_t lock;
int num_jobs;
// called by main
int numJobs()
{
pthread_spin_lock(&lock);
int res = num_jobs;
pthread_spin_unlock(&lock);
return res;
}
// called by thread_func
void decNumJobs()
{
pthread_spin_lock(&lock);
--num_jobs;
pthread_spin_unlock(&lock);
}
int main()
{
pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
// the other stuff as before
pthread_spin_destroy(&lock);
return 0;
}
Another alternative would be with pthread_cond_wait and pthread_cond_signal (mainly to avoid the sleep in the while loop, continue after receiving the signal and not based on a fixed amount of time).
e.g.
#include <pthread.h>
int num_jobs;
pthread_cond_t cond;
pthread_mutex_t lock;
void decNumJobs()
{
pthread_mutex_lock(&lock);
if (--num_jobs == 0)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
decNumJobs();
pthread_exit(0);
}
int main()
{
num_jobs = THREADS;
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
create_threads(THREADS);
pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
join_threads();
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&lock);
return 0;
}
Note: For the sake of simplicity, there is no error checking nor handling. Reading the documentation of the pthread_* functions (return values, interrupted wait, etc) is strongly advised.
I'm doing some university tasks and I managed to change the code and achieve the task properly but the console bugs out and acts strange.
The image can be found here since I don't have 10 reputation yet
https://imgur.com/a/X7a6bpa
You have the linux Ubuntu LED console and you can toggle the white and red lights as well as increase or decrease the speed at which they flash between a max and min amount.
The task was to have the console write out the current state of leds and the delay at which they flash.
Now I made that but due to interference, wrong semaphore usage or some code errors the console starts having random numbers appear in different parts of it. I've searched and couldn't find any reason for it. I'm also not sure what I'm actually looking at so an answer might already exist.
This is running Ubuntu 16.04.6 Xebian as that's what the uni requires. It includes threads and semaphores. I tried changing the semaphores and code around but it didn't work. I'm also fairly new to threads and semaphores so they might be completely in the wrong places.
I added as little code as possible. The things I wrote are the *led_info_thr function and creation in main,the semaphore in *led_toggle_thr.
static bool flashing[2] = {false, false};
static int flashing_delay[2] = {FLASH_INITIAL_DELAY, FLASH_INITIAL_DELAY};
static sem_t mutex;
void *led_toggle_thr(void *arg);
void *keyboard_thr(void *arg);
void *led_info_thr(void *arg);
void inc_delay(int i);
void dec_delay(int i);
int main (void) {
pthread_t thread[4];
int rc;
unsigned long i;
sem_init(&mutex,0 ,1);
console_init();
for (i = 0; i < 3; i += 1) {
rc = pthread_create(&thread[i], NULL, led_toggle_thr, (void *)i);
assert(rc == 0);
}
rc = pthread_create(&thread[2], NULL, keyboard_thr, NULL);
assert(rc == 0);
rc = pthread_create(&thread[3], NULL, led_info_thr, NULL);
assert(rc == 0);
while (true) {
/* skip */
}
exit(0);
}
void *led_toggle_thr(void *arg) {
unsigned long id = (long)arg;
while (true) {
if (flashing[id]) {F
sem_wait(&mutex);
led_toggle((leds_t)id);
sem_post(&mutex);
}
usleep(flashing_delay[id]);
}
}
void *led_info_thr(void *arg) {
char flashing_str[2]={'N','N'};
while(true)
{
for(int i = 0; i < 2; i++)
{
if(flashing[i] == true) flashing_str[i] = 'Y';
else flashing_str[i] = 'N';
sem_wait(&mutex);
lcd_write_at(i, 0, "LED%d F:%c D:%d", i, flashing_str[i], flashing_delay[i]);
sem_post(&mutex);
}
}
return NULL;
}
`
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.
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