Reputation: 609
I am trying to code a C project to simulate air traffic control in an airline. There is a Plane struct that has to have a mutex lock and cond.
This is the struct:
typedef struct Plane {
int ID;
int arrival_time;
pthread_mutex_t lock;
pthread_cond_t cond;
}Plane;
And there are landing/departing functions that create and use Plane
structures. However, I do not know how to initialize a struct's mutex lock inside a function.
void landing_func(int arrival_time)
{
Plane plane;
plane.ID = ++plane_id;
plane.arrival_time = arrival_time;
// initialize lock and cond here
};
However, I am not sure how to do that. I also declare a function that creates and returns a Plane*
Plane* createPlane(int arrival_time){
Plane* plane;
plane = (Plane*)malloc(sizeof(Plane));
plane->arrival_time = arrival_time;
plane->ID = ++plane_id;
pthread_mutex_init(&plane->lock, NULL);
pthread_cond_init(&plane->cond, NULL);
return plane;
};
I am not sure about correctness of this initialization.
A minor question: Can I return Plane
instead of Plane*
? I need Plane
in other functions instead of Plane*
.
Upvotes: 0
Views: 3267
Reputation: 180286
However, I do not know how to initialize a struct's mutex lock inside a function.
It's unclear what your confusion is.
The mutex and condition variable initialization functions require as first argument a pointer to the object to initialize, which is perfectly natural. Their second arguments can be null pointers if you want default attributes, which you probably do.
Given
Plane plane;
, as in your first example, the mutex you want to initialize is plane.lock
. The address-of operator will produce a pointer to it: &plane.lock
(or if you're uncertain about precedence and too lazy to look it up, then &(plane.lock)
avoids the precedence question). Thus, you might initialize it with
pthread_mutex_init(&plane.lock, NULL);
Similar for the CV.
I guess the main thing to appreciate is that the mutex being a member of a structure does not constitute a special case. Objects that are structure members or array elements have the same properties as objects of the same type that are not contained in such aggregates. The difference is simply in how you reference such objects.
I also declare a function that creates and returns a
Plane*
[...] I am not sure about correctness of this initialization.
It's fine, as you should also be able to infer from my previous comments.
A minor question: Can I return
Plane
instead ofPlane*
? I needPlane
in other functions instead ofPlane*
.
I take it that you're referring specifically to the second example, where you allocate space dynamically for the Plane
. Yes, you can return a Plane
instead of a Plane *
, supposing that you adjust the function's return type, but that defeats the purpose of the dynamic allocation. Moreover, if you do that naively (just return *plane;
, for example) then you will leak memory.
But it is extremely important to understand that when you pass or return an object, you are delivering a copy of that object to the receiver. Where once there was one, suddenly there are two.* Additionally, it is a shallow copy, so the two might not be wholly independent. That can be ok under some circumstances, but yours are not such circumstances. I guarantee that passing your Plane
structures around that way will cause you no end of grief in your particular program, on account of its reliance on the mutex and CV belonging to each. There are other gotchas there, too, but the mutex and CV are at the center of the most glaring ones.
Do yourself a tremendous favor, and adjust to exchanging Plane
s via pointer instead of by copying. It may take some adjustment, and that mode has its own issues to contend with, but trust me: the other way leads to disaster for you.
* This applies just as much to pointers as to any other kind of object, but if you pass a copy of a pointer then only the pointer itself is copied, and the copy points to the same object as the original does.
Upvotes: 1