I'm trying to have a thread, that waits until a task is assigned and then will do it, however I'm running into complications.
#include "dispatchQueue.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
task_t *task;
void test1() {
sleep(1);
printf("test1 running\n");
}
void* do_stuff(void *args) {
printf("in do stuff\n");
pthread_mutex_lock(&mutex);
printf("after do stuff has lock\n");
task_t *task = (task_t *)args;
(task->work) (task->params);
pthread_mutex_unlock(&mutex);
}
int main(int argc, char** argv) {
pthread_t thread;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_mutex_lock(&mutex);
printf("after main gets lock\n");
pthread_create(&thread, NULL, do_stuff, task);
task = task_create(test1, NULL, "test1");
pthread_mutex_unlock(&mutex);
printf("after main unlocks \n");
pthread_join(thread, NULL);
}
The above code will give a segfault, however if I switch the lines pthread_create and task = task_create(), then it works fine. I'm not familiar with C at all, so I'm wondering why this is?
This is how task is created if that helps, at this point I'm pretty sure it's a problem with the way I'm using pthreads.
task_t *task_create(void (*work)(void *), void *param, char* name) {
task_t *task_ptr = malloc(sizeof(task_t));
if (task_ptr == NULL) {
fprintf(stderr, "Out of memory creating a new task!\n");
return NULL;
}
task_ptr->work = work;
task_ptr->params = param;
strcpy(task_ptr->name, name);
return task_ptr;
}
pthread_create(&thread, NULL, do_stuff, task);
task = task_create(test1, NULL, "test1");
You're passing junk to the thread. You haven't set task to any particular value here, yet you pass it to the thread as a parameter.
void* do_stuff(void *args) { // *** args is garbage here
printf("in do stuff\n");
pthread_mutex_lock(&mutex);
printf("after do stuff has lock\n");
task_t *task = (task_t *)args; // ** So task is garbage here
(task->work) (task->params);
pthread_mutex_unlock(&mutex);
}
Here, you initialize task from args. But args has a garbage value.
If you have some kind of collection that's going to track what tasks a thread is going to work on, you have to pass the thread a parameter that allows it to reliably find that collection. In this particular case, &task would work.
Related
I have a school project that requires me to wrote a program printing this: <ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE>….............. using 3 threads and mutex. I have tried to do it with some help of the class, but it just keeps printing only <ONE>. Can you help me solve my problem and understand what have i wrong?
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *func(void *arg)
{
pthread_mutex_lock(&mutex);
while (1) {
printf ("<ONE>");
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void *func2(void *arg)
{
pthread_mutex_lock(&mutex);
while (1) {
printf ("<TWO>");
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void *func3(void *arg)
{
pthread_mutex_lock(&mutex);
while (1) {
printf ("<THREE>");
}
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
main()
{
pthread_t mythread1,mythread2,mythread3;
pthread_create( &mythread1, NULL, func, (void *) 1);
pthread_create( &mythread2, NULL, func2, (void *) 2);
pthread_create( &mythread3, NULL, func3, (void *) 3);
pthread_join ( mythread1, NULL);
pthread_join ( mythread2, NULL);
pthread_join ( mythread3, NULL);
exit(0);
}
As I made clear in the comments, this will get stuck in an infinite loop because you are doing the locking and unlocking outside the loop. First step is to move them inside.
void *func(void *arg)
{
while (1) {
pthread_mutex_lock(&mutex);
printf ("<ONE>");
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
Next, we need to add synchronization. An easy way to do that is to declare a global variable:
int next = 1;
Then we modify the function like this:
void *func(void *arg)
{
while (1) {
while(1) {
pthread_mutex_lock(&mutex);
if(next == 1) break;
pthread_mutex_unlock(&mutex);
}
printf ("<ONE>");
next = 2;
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
In func2 and func3 you need to modify if(next == 1) and next = 2 to appropriate values. func2 should have 2 and 3 while func3 should have 3 and 1.
This method is called busy waiting and is often not the best choice since it's quite cpu intense. A better alternative would be to look into pthread_cond_wait(). You can read about it here: http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_wait.html
Working from this example:
https://computing.llnl.gov/tutorials/pthreads/samples/hello.c
I've worked backwards and tried to edit in what I'm hoping to accomplish.
I'd like to pass data to the thread being spawned.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
long NUM_THREADS=0;
void *Entropy(void *depth)
{
long tid;
tid = (long)depth;
printf("This is where things get done.\n", tid);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
NUM_THREADS = sysconf(_SC_NPROCESSORS_ONLN);
printf("Cores: %i\n", NUM_THREADS);
pthread_t threads[NUM_THREADS];
int rc;
long t;
int depth;
depth = atoi(argv[1]);
for(t=0;t<NUM_THREADS;t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
I see on line:
rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);
My function Entropy gets called here, so I thought I'd try to tack on some brackets and pass a variable to that function the way I'd seen it done before. This seems to be a little different though, since this whole line returns something to rc, I wonder if that changes how I pass data to my thread, but I'm not sure how else I'd do it.
Right now this code compiles and runs, int main() goes fine without a hitch but it seg faults the moment it tries to create new threads.
In order to pass data to a thread you need to prepare the data in some place in memory, and pass a pointer to that place into pthread_create. It is pthread_create's job to pass that pointer to the runner function of your thread:
typedef struct {
long tid;
int depth;
}thread_data;
...
void *Entropy(void *dataPtr) {
thread_data *data= (thread_data*)dataPtr;
printf("This is where things get done for %li.\n", data->tid);
pthread_exit(NULL);
}
...
pthread_t threads[NUM_THREADS];
thread_data data[NUM_THREADS];
...
for(t=0;t<NUM_THREADS;t++) {
data[t].tid = t;
data[t].depth = depth;
rc = pthread_create(&threads[t], NULL, Entropy, (void *)&data[t]);
}
Your code crashes since you pass incorrect parameters:
rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);
// ^^^^^^^^^^^^^^
Here you should pass function pointer void *(*)(void *) but you are passing void *, and moreover value is unspecified since Entropy() has no return statement (did you turn warnings on at all?). I guess it should be like this:
rc = pthread_create(&threads[t], NULL, Entropy, (void *)t);
Next, how to pass parameter to thread routine? Technically you can use any pointer, but you should think twice about what you are passing. First of all pointed data must be valid when new thread runs. I.e. you shouldn't pass addresses of any locals except if you are sure that thread is finished when you are leaving scope of passed data - use pthread_join(new_thread) at the scope end to achieve that. Another approach is to pass pointer to data at global scope, that is surely valid at any moment. But there is one flaw - such data are visible to all threads, so you may accidentally make a mess. To avoid it - use dynamic memory - allocate data block with malloc() pass pointer to thread and free it in that thread. Latter option reduces chances to corrupt someone's else data.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
long NUM_THREADS=0;
void *Entropy(void *depth)
{
long tid = *((long *)depth);
free(depth);
printf("This is where things get done.\n", tid);
return NULL;
}
int main(int argc, char *argv[])
{
NUM_THREADS = sysconf(_SC_NPROCESSORS_ONLN);
printf("Cores: %i\n", NUM_THREADS);
pthread_t threads[NUM_THREADS];
int rc;
long t;
int depth;
depth = atoi(argv[1]);
for(t=0;t<NUM_THREADS;t++){
long *arg = malloc(sizeof(*arg));
*arg = t;
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, Entropy, arg);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
for(t=0;t<NUM_THREADS;t++){
pthread_join(threads[t], NULL);
}
}
I've never worked with pthreads before and am simply trying to familiarize myself with them. As such, I've written the following test code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int count = 0;
void *increment(void *tex);
int main(int argc, char **argv) {
pthread_t t1, t2, t3;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, NULL, &increment, &mutex);
pthread_create(&t2, NULL, &increment, &mutex);
pthread_create(&t2, NULL, &increment, &mutex);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
printf("Value of count is: %d\n", count);
}
void *increment(void *tex) {
pthread_mutex_t *mutex = (pthread_mutex_t *) mutex;
for (int i = 0; i < 100; i++) {
pthread_mutex_lock(mutex);
count++;
pthread_mutex_unlock(mutex);
}
return NULL;
}
I'm compiling the code with GCC using the proper -pthread flag, yet, for whatever reason, any time that any of the threads reach the mutex locking line, segfault. Upon further investigation with GDB, I've discovered that the mutex pointer appears to be invalid inside of the increment function even though I initialized it in main, passed it in as the argument to pthread_create, and have called join on each thread to ensure that main is still in scope. I'm at a loss for why this is happening, and could use some help. Thanks!
You've got:
pthread_mutex_t *mutex = (pthread_mutex_t *) mutex;
what you need is:
pthread_mutex_t *mutex = (pthread_mutex_t *) tex;
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
int global;
int i = 30;
int j = 30;
int k = 30;
pthread_mutex_t mutex;
void* child1(void* arg)
{
while(k--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from child1\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
}
void* child2(void* arg)
{
while(j--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from child1\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid1, tid2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid1, NULL, child1, NULL);
pthread_create(&tid2, NULL, child2, NULL);
while(i--)
{
pthread_mutex_lock(&mutex);
global++;
printf("from main\n");
printf("%d\n",global);
pthread_mutex_unlock(&mutex);
}
return 0;
}
I'm new to pthread and multithreading, the result of this code is from main xx and child1 appeared rarely, the three threads never appear together, what's the problem?
Most of time in the critical sections will be spent in the printf calls. You might try:
{
int local;
pthread_mutex_lock(& mutex);
local = ++global;
pthread_mutex_unlock(& mutex);
printf("from <fn>\n%d\n", local);
}
This still doesn't give any guarantee of 'fairness' however, but the printf call is very likely to use a system call or I/O event that will cause the scheduler to kick in.
Your program is similar to the Dining Philosophers Problem in many respects. You don't want any thread to 'starve', but you have contention between threads for the global counter, and you want to enforce an orderly execution.
One suggestion in code replace printf("from child1\n"); to printf("from child2\n"); in void* child2(void* arg) function. And if you want ensure all threads to complete please add the following lines at end of main function.
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
I think you should use 3 differents mutex , by the way use pconditional control in order to avoid having unsafe access
I have 4 threads to create thread1, thread2, thread3 and thread4:
pthread_create(thread1,NULL,thread_func1,NULL);
pthread_create(thread2,NULL,thread_func2,NULL);
pthread_create(thread3,NULL,thread_func3,NULL);
pthread_create(thread4,NULL,thread_func4,NULL);
looking in the debug , The order of launched threads is not the same as defined in the source code.
Are there a solution to launch the threads with an order that I could define?
The launch order is sequential, in that the create calls happen in the order they're written.
However the scheduler for whatever reason isn't scheduling the newly launched threads in the order you hoped. If the order matters perhaps threads isn't what you want? The big advantage with threads is that they don't always get scheduled in a sequential order!
If you really want though you can use synchronisation primitives (e.g. a series of mutexes, or a condvar) to ensure that up to a certain point happens in predictable order, but from that point onwards the order will still be down to the whims of the scheduler. As an example this code guarantees that each thread will print its ID in the order they were created:
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void sync_threads(const int num, int *cur) {
pthread_mutex_lock(&mut);
while (*cur != num) {
pthread_cond_wait(&cond, &mut);
}
// Do work that must happen in order here:
printf("Thread: %d\n", num);
++*cur;
pthread_mutex_unlock(&mut);
pthread_cond_broadcast(&cond);
}
static int num = 1;
void *thread1(void *d) {
sync_threads(1,&num);
while (1); // Rest of work happens whenever
return NULL;
}
void *thread2(void *d) {
sync_threads(2,&num);
while (1);
return NULL;
}
void *thread3(void *d) {
sync_threads(3,&num);
while (1);
return NULL;
}
void *thread4(void *d) {
sync_threads(4,&num);
while (1);
return NULL;
}
int main() {
pthread_t t1,t2,t3,t4;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_create(&t3, NULL, thread3, NULL);
pthread_create(&t4, NULL, thread4, NULL);
while(1) {
// some work
}
}
I've used while(1); to simulate some real work happening. It does this with a mutex protecting the "current" thread, i.e. the order of initialisation and then a condvar to make sleeping/waking possible. It broadcasts to all threads who then check to see which one is up next. You could design as system that skips the broadcast, but that complicates things for relatively little gain.
You can also add more synchronisation if required at other points, but the more you synchronise things the less point there is in having threads in the first place.
Ideally if things need to happen in a predictable order they should be done before spawning threads, not as soon as the threads spawn, e.g.:
fixed_init_for_thread1();
fixed_init_for_thread2();
fixed_init_for_thread3();
fixed_init_for_thread4();
pthread_create(thread1,NULL,thread_func1,NULL);
pthread_create(thread2,NULL,thread_func2,NULL);
pthread_create(thread3,NULL,thread_func3,NULL);
pthread_create(thread4,NULL,thread_func4,NULL);
such that by the time the threads are created you don't care which one actually gets given the chance to run first.
I don't think you really care which thread executed first. If you just need an unique identifier for the four threads, check pthread_self. To have sequential IDs, call the ID allocator from within the thread; or generate the ID and pass it as user parameter when calling pthread_create.
here after the solution I used
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static bool wait = TRUE;
void thread_sync() {
pthread_mutex_lock(&mut);
wait = FALSE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
}
void thread_wait_sync() {
pthread_mutex_lock(&mut);
if (wait==TRUE)
{
pthread_cond_wait(&cond,&mut);
}
wait = TRUE;
pthread_mutex_unlock(&mut);
}
void *thread1(void *d) {
thread_sync();
while (1); // Rest of work happens whenever
return NULL;
}
void *thread2(void *d) {
thread_sync();
while (1);
return NULL;
}
void *thread3(void *d) {
thread_sync();
while (1);
return NULL;
}
void *thread4(void *d) {
while (1);
return NULL;
}
int main() {
pthread_t t1,t2,t3,t4;
pthread_create(&t1, NULL, thread1, NULL);
thread_wait_sync();
pthread_create(&t2, NULL, thread2, NULL);
thread_wait_sync();
pthread_create(&t3, NULL, thread3, NULL);
thread_wait_sync();
pthread_create(&t4, NULL, thread4, NULL);
while(1) {
// some work
}
}
Move 'pthread_create(thread2,NULL,thread_func2,NULL);' into thread_func1()
Move 'pthread_create(thread3,NULL,thread_func2,NULL);' into thread_func2()
Move 'pthread_create(thread4,NULL,thread_func2,NULL);' into thread_func3()
This is VERY close to the other question posted recently and just as err.. 'strange'