0

I have finally got so far to create an accurate consumer-producer type model for some test application I am making but the last bit is causing me some problems.

I have 2 structs set-up for my application. One is used for a linked list which is used as a list of work that has to be done. The other one is a struct specific to each thread which contains a double pointer to the linked list. I don`t use a single pointer as then I am unable to modify the pointer in one thread and detect a change in the other.

//linked list struct:

typedef struct list_of_work list_of_work;
struct list_of_work {
    // information for the work 

    list_of_work        *next;

};

//thread struct:

typedef struct thread_specs {

    list_of_work         **linked_list;

    unsigned short       thread_id;

    pthread_mutex_t      *linked_list_mtx;

} thread_specs;

the double pointer in thread_specs get bound to a double pointer of the root of the list_of_work struct like so:

in main:

list_of_work                         *root;
list_of_work                         *traveller;
pthread_t                            thread1;
thread_specs                         thread1_info;

// allocating root and some other stuff
traveller = root;
thread1_info.linked_list = &traveller;

This all works without warnings or errors.

now I go on to create my pthread with:

pthread_create(&thread1, NULL, worker, &thread1_info )

and in my pthread I perform 2 casts, 1 to cast the thread_info struct and the other to cast the linked list. ptr is my argument:

thread_specs            *thread = (thread_specs *)ptr;
list_of_work            *work_list = (list_of_work *)thread->linked_list;
list_of_work            *temp;

this throws no errors.

I then have a function which is called list_of_work *get_work(list_of_work *ptr), the function works so I won't post the entire thing but as you can see it expects to see a pointer to the linked list and it returns a pointer of the same linked list(which is either NULL or is the next piece of work).

So I use this function to get the next piece of work like this:

temp = get_work(*work_list);
if (temp != NULL) {
    work_list = &temp;
    printf("thread: %d || found work, printing type of work.... ",thread->thread_id);
}

Now this is the crux. How can I correctly cast and pass the pointer BEHIND the first pointer to my get_work() function so it can do what it does.

my compiler spits warnings:

recode.c:348:9: error: incompatible type for argument 1 of ‘get_work’
recode.c:169:14: note: expected ‘struct list_of_work *’ but argument is of type ‘list_of_work’

I thank whoever can hep me!

  • `thread->drives` : there is no such member. Perhaps posting the *real* code would be helpful. – WhozCraig Jun 27 '14 at 21:28
  • ah it is real code. I just changes some references to make my intentions clearer –  Jun 27 '14 at 21:32
  • 1
    The cast is also incorrect (and its seeming-necessity should be a red-flag that its not right). `list_of_work *work_list = (list_of_work *)thread->linked_list;` should be `list_of_work *work_list = *(thread->linked_list);`, though honestly if you're trying to share and mutex-control a single linked list head pointer this isn't the way to do it. – WhozCraig Jun 27 '14 at 21:36
  • this is my first time working with pthread and linked list... how would you suggest I share a single linked list? The only much less complex way to do it would be to share it global but I don`t really like to do that –  Jun 27 '14 at 21:40
  • if you haven't a strong feel for how pthreads work (irrespective of linked lists) that is going to be a significant hindrance to implementing your solution. I would suggest spending a little time on that first, in particular how pthread mutexes , condition variables, and their interaction as a signaling mechanism work. The linked list management within that paradigm is *almost* a separate issue (though related in the fact that the former will play a role in how you implement the latter). – WhozCraig Jun 27 '14 at 21:59
  • I do understand mutex, condition variables and signalling. My original implementation was using a predicate condition with a `pthread_cond_wait()`. However today someone recommended me to use linked list instead and I read about it and it after 5-6 hours I got to this point where I have a linked list and this is basically my last hurdle. Is there a reason why it is bad that I to a cast twice? I mean I don`t have to do that but then I`d have to write more if I want to acces those variables names(I have to go through the thread_specs struct and then to the work_list). –  Jun 27 '14 at 22:02
  • Ah. That makes sense. For your implementation it is the list head pointer itself (by address) that must be shared with all the threads in your paradigm. The noted incorrect cast i mentioned dodges that by pulling it *by-value*. I think you had the right idea going in, just lost it there. you need to keep that level of indirection (pointer to the list head pointer) intact, as that and its underlying management data is the crux of your logical predicate-state. I.e., there can be only one head. Iow, I think you're close if you grasp muteness and cond-vars like you claim. – WhozCraig Jun 27 '14 at 22:06
  • And you don't need a global for this, on that you are quite-correct. – WhozCraig Jun 27 '14 at 22:07
  • I don`t want to share the list head pointer(exept ofcourse at the very beginning). I want to share the current position of the of the linked list. Of course I have protected acces to it with the same mutex across all worker threads. I use the double pointer because I cannot change a single pointer globally for all threads. Whereas with a double pointer I can change the second pointer and all threads share the same position. –  Jun 27 '14 at 22:10
  • So you just want to enumerate the linked list via a shared pointer? the threads themselves aren't responsible for adding-to or taking-from the linked list, its just an enumerated shared walk-through? that gets *considerably* simpler if that is the case. – WhozCraig Jun 27 '14 at 22:17
  • the worker threads themselves do not add anything to the linked list. they do modify variables within a single instance of it. I append things to the list with a producer thread. This is a through a different pointer though. Producer thread works without problems. The producer thread is a singular thread so I don`t have to worry about it having to share the pointer with a different thread. The producer and worker threads do share the linked_list_mtx to make sure no reading or writing occurs simultaneously. –  Jun 27 '14 at 22:27
  • if you would allow, I can post some workable code. will take me a few minutes though –  Jun 27 '14 at 22:33
  • 1
    No worries. I think [**this**](http://pastebin.com/Hh3eNUZ2) is what you're trying to do, but i'm probably oversimplifying things quite a bit. it gets more difficult when you have active inserters while threads are perusing the list, but for just a simpler multi-thread enumeration a single mutex is really all you need. And not even that with the right atomic intrinsics. – WhozCraig Jun 27 '14 at 22:42
  • http://pastebin.com/nWLbLzgz have code the perfect example now. It is rather crude with some hacks but it show my problem! You have to press a enter to wake up a thread. But as you can see the each thread prints out the work on its own without a kind of share between worklist which I need. the cast you posted earlier worked to silence the error by the way –  Jun 27 '14 at 23:46
  • thank you with your code example I was able to fix it! –  Jun 29 '14 at 04:31

1 Answers1

0

Based on the function get_work()'s definition you posted and error message, this issue here:

temp = get_work(work_list);
                ^
   /* Notice there's no dereferencing here */

The function expects a pointer to struct list_of_work whereas you pass a struct list_of_work.

P.P
  • 117,907
  • 20
  • 175
  • 238