here is my code and I want to write it with out deadlock in c. How can I change it?
void *
philosopher (void * _args)
{
/* Cast the args as struct with self identifier, semaphores */
struct args *args = (struct args *) _args;
int self = args->self; /* unique thread identifier */
int next = (self + 1) % SIZE;
sem_wait (args->sems[self]); /* pick up left fork */
sem_wait (args->sems[next]); /* pick up right fork */
/* Critical section (eating) */
sem_post (args->sems[next]); /* put down right fork */
sem_post (args->sems[self]); /* put down left fork */
/* Do other work and exit thread */
}
To avoid deadlock in your code, you can use a semaphore with a non-zero initial value, to make sure that each philosopher picks up the forks in the same order.
By locking the forks with a semaphore, and having each philosopher acquire the lock prior to picking up the forks.
Here is an updated version of the code, that avoids deadlocks.
void *
philosopher (void * _args)
{
/* Cast the args as struct with self identifier, semaphores */
struct args *args = (struct args *) _args;
int self = args->self; /* unique thread identifier */
int next = (self + 1) % SIZE;
/* Acquire lock for forks */
sem_wait (args->lock);
/* Pick up left fork */
sem_wait (args->sems[self]);
/* Pick up right fork */
sem_wait (args->sems[next]);
/* Release lock for forks */
sem_post (args->lock);
/* Critical section (eating) */
sem_post (args->sems[next]); /* put down right fork */
sem_post (args->sems[self]); /* put down left fork */
/* Do other work and exit thread */
}
Related
I'm learning THE LINUX PROGRAMING INTERFACE this book and get confused here.
I invoke the pthread_attr_getdetachstate() and find that thread created by mq_notify() it's JOINABLE, but how to pthread_join() this zoomble(after it terminated) thread?
I saw the man page, but he doesn't use join.
I just looked at the glibc source code for mq_notify.
mq_notify starts a single control thread with PTHREAD_CREATE_DETACHED. Therefore, it is not joinable.
The pthread_t value that gets set by the call from mq_notify to pthread_create is not available to you. So, whatever value you're using in your pthread_attr_getdetachstate call has no relationship to the mq_notify call.
This control thread created by mq_notify may create other threads. But, they also run detached [using pthread_detach(pthread_self())].
UPDATE:
I wonder whether the OP is talking about using SIGEV_THREAD to receive message notifications. It makes some sense that they would want to know about how to manage the thread in which their specified function is called. – John Bollinger
In the glibc wrapper function mq_notify ...
The first time mq_notify is called, it creates a netlink socket for communication and a single control thread.
In the sigevent struct [from caller], if sigev_notify is SIGEV_THREAD, the struct can have a [non-null] pthread_attr_t * value in sigev_notify_attributes. These attributes are copied and passed off to the actual mq_notify syscall via an internal struct
This is because although the syscall could create a thread [via an internal clone call], it could not do this from a signal handler and all the things that pthread_* functions do to (e.g.) set up pthread_t could not be done by the kernel.
So, after that, the [internal] struct is [ultimately] sent to the control thread [from the kernel] via a message on the netlink socket. The thread function for the control thread is [in the code below]: helper_function
The control thread will set the attributes from that message/struct into the pthread_create call it issues to start a [per-message] notification thread.
But ... The start routine specified in the pthread_create is not caller's notification/thread function. It is another wrapper function (e.g. notification_function) that calls pthread_detach as I mentioned above. It then calls user's start function.
I could be misreading the code, but, AFAICT, by the time the user's callback function has been invoked, it is in a separate thread that has already been detached.
So, again, the thread is not joinable. Whether the pthread_detach call updates the attributes of the per-message thread so that the caller can do: pthread_attribute_getdetachstate(pthread_self(),...) and get this is a bit of a moot point. We know it's detached.
So, user/caller's thread function can't pthread_join itself. And, caller's original thread can no longer manage the notification thread [because, again, it's detached], there really isn't anything to do [or anything that can be done].
Here's an excerpt from sysdeps/unix/sysv/linux/mq_notify.c:
/* The function used for the notification. */
static void *
notification_function(void *arg)
{
/* Copy the function and parameter so that the parent thread can go on with its life. */
volatile union notify_data *data = (volatile union notify_data *) arg;
void (*fct) (union sigval) = data->fct;
union sigval param = data->param;
/* Let the parent go. */
(void) __pthread_barrier_wait(¬ify_barrier);
/* Make the thread detached. */
(void) pthread_detach(pthread_self());
/* The parent thread has all signals blocked. This is probably a bit surprising for this thread. So we unblock all of them. */
(void) change_sigmask(SIG_UNBLOCK, NULL);
/* Now run the user code. */
fct(param);
/* And we are done. */
return NULL;
}
/* Helper thread. */
static void *
helper_thread(void *arg)
{
while (1) {
union notify_data data;
ssize_t n = __recv(netlink_socket, &data, sizeof(data),
MSG_NOSIGNAL | MSG_WAITALL);
if (n < NOTIFY_COOKIE_LEN)
continue;
if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP) {
/* Just create the thread as instructed. There is no way to report a problem with creating a thread. */
pthread_t th;
if (__builtin_expect(pthread_create(&th, data.attr, notification_function, &data)
== 0, 0))
/* Since we passed a pointer to DATA to the new thread we have to wait until it is done with it. */
(void) __pthread_barrier_wait(¬ify_barrier);
}
else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
/* The only state we keep is the copy of the thread attributes. */
free(data.attr);
}
return NULL;
}
static void
reset_once(void)
{
once = PTHREAD_ONCE_INIT;
}
static void
init_mq_netlink(void)
{
/* This code might be called a second time after fork(). The file descriptor is inherited from the parent. */
if (netlink_socket == -1) {
/* Just a normal netlink socket, not bound. */
netlink_socket = __socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, 0);
/* No need to do more if we have no socket. */
if (netlink_socket == -1)
return;
}
int err = 1;
/* Initialize the barrier. */
if (__builtin_expect(__pthread_barrier_init(¬ify_barrier, NULL, 2) == 0, 0)) {
/* Create the helper thread. */
pthread_attr_t attr;
(void) pthread_attr_init(&attr);
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/* We do not need much stack space, the bare minimum will be enough. */
(void) pthread_attr_setstacksize(&attr, __pthread_get_minstack(&attr));
/* Temporarily block all signals so that the newly created thread inherits the mask. */
sigset_t oss;
int have_no_oss = change_sigmask(SIG_BLOCK, &oss);
pthread_t th;
err = pthread_create(&th, &attr, helper_thread, NULL);
/* Reset the signal mask. */
if (!have_no_oss)
pthread_sigmask(SIG_SETMASK, &oss, NULL);
(void) pthread_attr_destroy(&attr);
if (err == 0) {
static int added_atfork;
if (added_atfork == 0 && pthread_atfork(NULL, NULL, reset_once) != 0) {
/* The child thread will call recv() which is a cancellation point. */
(void) pthread_cancel(th);
err = 1;
}
else
added_atfork = 1;
}
}
if (err != 0) {
__close_nocancel_nostatus(netlink_socket);
netlink_socket = -1;
}
}
/* Register notification upon message arrival to an empty message queue
MQDES. */
int
mq_notify(mqd_t mqdes, const struct sigevent *notification)
{
/* Make sure the type is correctly defined. */
assert(sizeof(union notify_data) == NOTIFY_COOKIE_LEN);
/* Special treatment needed for SIGEV_THREAD. */
if (notification == NULL || notification->sigev_notify != SIGEV_THREAD)
return INLINE_SYSCALL(mq_notify, 2, mqdes, notification);
/* The kernel cannot directly start threads. This will have to be done at userlevel. Since we cannot start threads from signal handlers we have to create a dedicated thread which waits for notifications for arriving messages and creates threads in response. */
/* Initialize only once. */
pthread_once(&once, init_mq_netlink);
/* If we cannot create the netlink socket we cannot provide SIGEV_THREAD support. */
if (__glibc_unlikely(netlink_socket == -1)) {
__set_errno(ENOSYS);
return -1;
}
/* Create the cookie. It will hold almost all the state. */
union notify_data data;
memset(&data, '\0', sizeof(data));
data.fct = notification->sigev_notify_function;
data.param = notification->sigev_value;
if (notification->sigev_notify_attributes != NULL) {
/* The thread attribute has to be allocated separately. */
data.attr = (pthread_attr_t *) malloc(sizeof(pthread_attr_t));
if (data.attr == NULL)
return -1;
memcpy(data.attr, notification->sigev_notify_attributes, sizeof(pthread_attr_t));
}
/* Construct the new request. */
struct sigevent se;
se.sigev_notify = SIGEV_THREAD;
se.sigev_signo = netlink_socket;
se.sigev_value.sival_ptr = &data;
/* Tell the kernel. */
int retval = INLINE_SYSCALL(mq_notify, 2, mqdes, &se);
/* If it failed, free the allocated memory. */
if (__glibc_unlikely(retval != 0))
free(data.attr);
return retval;
}
I have to pass 3 separate values, say "10", "15", "20" that are stored in a child process to a parent process. I cannot use shared memory or pipes, only signals and handlers. How do I pass these values from a child to parent only using signals? I tried passing exit codes but you can only have one exit value. I need to pass 3 separate values. Any suggestions? In addition, my parent has two children. Both of these children have to pass 3 separate values of their own to the parent, so that the parent can add them in the end.
Send signal from child to parent using rt_sigqueueinfo(). You can use sigqueue() as well.
Please refer this example
send signal to parent with data
Well, as I promised in one of the comments, here's a solution to the problem. The first thing to say is that this solution does not work properly in Linux, as linux makes no warrant of signal delivery on high number of signals sent (when the target process doesn't get scheduled enough to handle them) so a BSD version has been used (also should run, but not tested on Mac OS/X and other unices). I'll explain the solution achieved in four steps, as the first probably is enough to pass the homework, but not enough to consider it a proper working way of passing information from child to parent. Also, due to limited space to post code, I've posted only the first version of the code and all the others must be downloaded from github (links provided).
The implementation has been made on a raspberry pi with freebsd 11.0 which makes delivery of signals reliable. The failing system was a Debian 9.4 with kernel version 4.9.0-6-amd64
FIRST VERSION
As the homework problem states, the only thing the parent is to do is to add the numbers and print the result. Then, a good plan is to encode a number, N, to the parent, as sending n signals of type SIGUSR1. The parent has only to count the signals and print the number when the child finishes (we determine this on a succesful return from the wait(2) system call)
child.c
/* 00001 */ #include <sys/types.h>
/* 00002 */ #include <sys/time.h>
/* 00003 */ #include <signal.h>
/* 00004 */ #include <stdio.h>
/* 00005 */ #include <stdlib.h>
/* 00006 */ #include <unistd.h>
/* 00007 */ #include <time.h>
/* 00008 */ #define F(fmt) "<%d>:"__FILE__":%d:%s: " fmt, my_pid, __LINE__, __func__
/* 00009 */ pid_t my_pid;
/* 00010 */ int main()
/* 00011 */ {
/* 00012 */ pid_t parent_pid = getppid();
/* 00013 */ struct timeval now;
/* 00014 */ gettimeofday(&now, NULL);
/* 00015 */ srand((int)now.tv_sec ^ (int)now.tv_usec);
/* 00016 */ my_pid = getpid();
/* 00017 */ int sum = 0;
/* 00018 */ int n = rand() % 3 + 1;
/* 00019 */ int i;
/* 00020 */ for (i = 0; i < n; i++) {
/* 00021 */ int number = rand() % 10 + 10;
/* 00022 */ printf(F("Sending %d\n"), number);
/* 00023 */ int j;
/* 00024 */ for (j = 0; j < number; j++) {
/* 00025 */ printf(F("kill(%d, SIGUSR1);\n"), parent_pid);
/* 00026 */ kill(parent_pid, SIGUSR1);
/* 00027 */ }
/* 00028 */ sum += number;
/* 00029 */ }
/* 00030 */ printf(F("my sum = %d\n"), sum);
/* 00031 */ }
(each child selects at random a number between 1 and 4 numbers, randomly in the range 10...19, and sends that number of SIGUSR1 signals to the parent)
The parent is so:
parent.c
/* 00001 */ #include <errno.h>
/* 00002 */ #include <signal.h>
/* 00003 */ #include <stdio.h>
/* 00004 */ #include <stdlib.h>
/* 00005 */ #include <string.h>
/* 00006 */ #include <sys/time.h>
/* 00007 */ #include <sys/types.h>
/* 00008 */ #include <sys/wait.h>
/* 00009 */ #include <time.h>
/* 00010 */ #include <unistd.h>
/* 00011 */ #define F(fmt) "[%d]:"__FILE__":%d:%s: " fmt, my_pid, __LINE__, __func__
/* 00012 */ #define NCHILDREN 8
/* 00013 */ char child[] = "child";
/* 00014 */ pid_t my_pid;
/* 00015 */ int sum = 0; /* here's where the number of signals is accumulated */
/* 00016 */ void handler(int sig, siginfo_t *info, void *unused)
/* 00017 */ {
/* 00018 */ switch (sig) {
/* 00019 */ case SIGUSR1: sum++; break;
/* 00020 */ }
/* 00021 */ }
/* 00022 */ int main()
/* 00023 */ {
/* 00024 */ int i;
/* 00025 */ my_pid = getpid();
/* 00026 */ struct sigaction sa, oldsa;
/* 00027 */ sa.sa_sigaction = handler;
/* 00028 */ sa.sa_flags = SA_RESTART; /* restart the wait(2) syscall below */
/* 00029 */ sigemptyset(&sa.sa_mask);
/* 00030 */ sigaddset(&sa.sa_mask, SIGUSR1);
/* 00031 */ sigaction(SIGUSR1, &sa, &oldsa);
/* 00032 */ pid_t res;
/* 00033 */ for (i = 0; i < NCHILDREN; i++) {
/* 00034 */ res = fork();
/* 00035 */ if (res > 0) /* parent */
/* 00036 */ continue;
/* 00037 */ else if (res < 0) {
/* 00038 */ fprintf(stderr,
/* 00039 */ F("ERROR: fork: %s (errno = %d)\n"),
/* 00040 */ strerror(errno), errno);
/* 00041 */ exit(EXIT_FAILURE);
/* 00042 */ } else { /* child */
/* 00043 */ execlp(child, child, NULL);
/* 00044 */ fprintf(stderr,
/* 00045 */ F("ERROR: exec: %s: %s (errno = %d)\n"),
/* 00046 */ child, strerror(errno), errno);
/* 00047 */ exit(EXIT_FAILURE);
/* 00048 */ }
/* 00049 */ }
/* 00050 */ while (wait(NULL) >= 0); /* wait for children until no more */
/* 00051 */ sigaction(SIGUSR1, &oldsa, NULL);
/* 00052 */ printf(F("sum = %d\n"), sum);
/* 00053 */ }
This example will make the parent to print the correct sum, as you can probe (linux fails dramatically printing in some cases just sum = 1, because it is only capable of processing the first signal of each type, leading to a single number of value 1) The problem with linux is that linux cannot ensure and deliver several signals if the receiver has not been scheduled enough for the system to be able to the signals and allow the handler to be called. Just inserting a sleep(1) in child.c after the kill(2) syscall of line 60 will do.
Many readers will complaint about the way the solution is implemented, as this is not a good way to pass info to the parent (no form of delimiting the numbers themselves to allow the parent to separate and identify them), and some way to differentiate the different numbers passed and someway to identify the sender to be included. So the parent not only wants to print the sum, but also which number comes from which child or a way to separate the different numbers for each child.
SECOND VERSION(first attempt)
In this version, we introduce the sigaction(2) syscall and its possibility of getting in the signal handler a way to identify the sender of such signal (SA_SIGINFO POSIX option). I refer the reader to the manual page, as it is well documented there (even for linux, that continues to handle signals without warrant the signal delivery) and files can be downloaded from here
Parent is far more complicated. It has a table for each child and a handler that extracts the signal's sender pid, searches for the child slot, and stores in it the accumulated number of signals received, and handling the SIGUSR2 signal as an end of data marker, that allows us to store the accumulated value.
The parent now prints the numbers received from each child and, if you try this example, you'll see another issue: The kernel does not warrant the order in which signals are delivered. This means that some SIGUSR1 signals belonging to a next number are handled before the SIGUSR2 signal finishing the previous number. So we cannot send new SIGUSR1 signals until the last SIGUSR2 signal has been sent and handled. We correct this introducing a delay sleep(1) in the next version:
THIRD VERSION (with delays)
On this version we introduce delays into the child program, so no number is sent until we have given time to the parent to handle all the pending signals. In this way, no SIGUSR2 corresponding to a next number is sent to the parent process before it has had time to process it. These are the files for this version
In this case, you'll observe the output is delayed at several points to allow for the parent to have the time to deliver pending signals before sending new ones.
VERSION FOUR (final version)
Our final approach tries to eliminate the delays, making the parent to send a signal to the child as soon as he has received a SIGUSR2, indicating the end of a number, to acknowledge the reception of the number and to allow the child to continue. I'll comment at the end some race condition, that can be saved with some code already included on it (As i'm limited in post space, I'll publish it on github and allow you to download it from there)
COMMENT ON THE RACE CONDITION
On final version, there's an unavoidable race condition in the child, as we cannot enable interrupts while in pause(2) syscall, so we cannot enter in the pause(2) system call with interrupts blocked, to unblock them inside and listen for the next interrupt. The lines in child.c:
00061: printf(F("kill(%d, SIGUSR2);\n"), parent_pid);
00062: sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL);
00063: yet_unacknowledged = 1;
00064: kill(parent_pid, SIGUSR2);
00065: sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
00066: while (yet_unacknowledged) sleep(1);
allow for the parent to be scheduled, send the ack signal, and the signal be handled between the check for yet_unacknowledged in the while loop and the sleep(1) statement. These lines where written initially as:
00066: pause(); /* wait for an interrupt */
but this way, sometimes the child gets blocked as the acknowledge signal has been delivered (and handled) between the kill from the child to the parent and the pause(2) syscall.
But after checking that there's no way to enable SIGUSR2 interrupts while executing pause() the only way to proceed is to consider that the handler has executed in between and execute just single sleep(1) once. Next loop pass, the check will fail and, at most we execute only one sleep call.
How to implement all of this in linux
Well, I have extended far more from my original target, and I will not show a complete working solution in linux. As linux cannot ensure that more of one signal is warranted to be delivered to a process, the only way to implement is to install a mechanism for the parent to acknowledge each received signal, and the child not to send the next signal until it has received the acknowledge of the previous. This is completeley out of scope for a beginners course on introduction to system calls (better on a course of networking protocols), so if you are interested, you'll have to ask your teacher for more info on this.
So i'm working on this code that is a producer-consumer code. It runs completely through the program, it just never actually executes anything in the critical section because it never really wakes up from sleep! I've added print statements everywhere to try to figure out where the code is executing, and it enters both producer and consumer functions, but never enters any portion of it after the sleep() function.
Here is my main:
/* 1. Get command line arguments argv[1], argv[2], argv[3] */
/* n1=arg[2], n2=arg[3]
/* 2. Initialize buffer, mutex, semaphores, and other global vars */
/*create the mutex lock */
/* create the semaphore and initialize it to 3 */
/*creating full semaphore and initializing it to 0 */
/*** critical section ***/
/* get the default attribute */
pthread_attr_init(&attr);
/* 3. Create producer thread(s) */
while (count < n1)
{
pthread_t tid;
/* create a new thread */
pthread_create(&tid, &attr, producer, NULL);
count++;
}
printf("OUTSIDE OF PRODUCER CREATION\n");
/* 4. Create consumer thread(s) */
count = 0;
while(count < n2)
{
pthread_t tid2;
/* create a new thread */
pthread_create(&tid2, &attr, consumer, NULL);
count++;
}
printf("after the crit section \n");
/* 5. Sleep */
/* 6. Realease resources, e.g destroy mutex and semaphores */
i've included for the most part just the code that I know i'm having a problem with and the rest are comments. and here is the code for my producer. consumer is basically the same:
void *producer(void *param) {
buffer_item rand;
unsigned int *seed;
seed = (unsigned int *)malloc(sizeof(unsigned int));
*seed = 10;
while (1) {
printf("Inside producer function\n");
/* Sleep for a random period of time */
r = (rand_r(seed))/divide;
sleep(r);
printf("producer slept\n");
//wait(empty)
//wait(mutex)
printf("producer locked mutex\n");
//crit section - add item to buffer
/*Generate a random number */
/*insert random number*/
printf("producer inserted item \n");
if (resp < 0)
printf("Producer error condition\n"); //Report error condition
//signal mutex
//signal empty
}
}
so when i run a.out 4 4 4, i get this as my output:
Inside producer function
Inside producer function
Inside producer function
OUTSIDE OF PRODUCER CREATION
Inside producer function
inside consumer function
inside consumer function
inside consumer function
after the crit section
inside consumer function
I'm not sure if its normal that things look like they are running out of order... it is executing 4 times but as you can see if never hits that print statement that happens after my sleep function (for both producer and consumer)
This is homework so i'm just looking for a bit more direction on this...
From the discussion, your error was that your sleep() values were too large, one you quoted coming out to 22 minutes. Rather than division(/) to limit the values, modulo(%) will put your values within a range. I recommend %10, or some other value which will limit the sleeps to a reasonable range.
I'm having trouble synchronizing a master thread to a recently started child thread.
What I want to do is:
master thread creates a new child thread and blocks
child thread starts and initializes (might take some time)
once the child thread is initialized, the main thread continues (and the two threads run in parallel)
My first attempt was something like:
typedef struct threaddata_ {
int running;
} threaddata_t;
void*child_thread(void*arg) {
threaddata_t*x=(threaddata_t)arg;
/* ... INITIALIZE ... */
x->running=1; /* signal that we are running */
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
x->running=0;
int result=pthread_create(&threadid, 0, child_thread, &running);
while(!x->running) usleep(100); /* wait till child is initialized */
/* MAIN THREAD BODY */
}
Now I didn't like this at all, because it forces the main thread to sleep for probably a longer period than necessary.
So I did a 2nd attempt, using mutexes&conditions
typedef struct threaddata_ {
pthread_mutex_t x_mutex;
pthread_cond_t x_cond;
} threaddata_t;
void*child_thread(void*arg) {
threaddata_t*x=(threaddata_t)arg;
/* ... INITIALIZE ... */
pthread_cond_signal(&x->x_cond); /* signal that we are running */
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
pthread_mutex_init(&x->x_mutex, 0);
pthread_cond_init (&x->x_cond , 0);
pthread_mutex_lock(&x->x_mutex);
int result=pthread_create(&threadid, 0, child_thread, &running);
if(!result)pthread_cond_wait(&x->x_cond, &x->x_mutex);
pthread_mutex_unlock(&x->x_mutex);
/* MAIN THREAD BODY */
}
This seemed more sane than the first attempt (using proper signals rather than rolling my own wait loop), until I discovered, that this includes a race condition:
If the child thread has finished the initialization fast enough (before the main thread waits for the condition), it will deadlock the main thread.
I guess that my case is not so uncommon, so there must be a really easy solution, but I cannot see it right now.
Proper way of condvar/mutex pair usage:
bool initialised = false;
mutex mt;
convar cv;
void *thread_proc(void *)
{
...
mt.lock();
initialised = true;
cv.signal();
mt.unlock();
}
int main()
{
...
mt.lock();
while(!initialised) cv.wait(mt);
mt.unlock();
}
This algorithm avoids any possible races. You can use any complex condition modified when mutex locked (instead of the simple !initialised).
The correct tool for that are sem_t. The main thread would initialize them with 0 and wait until it receives a token from the newly launched thread.
BTW your mutex/cond solution has a race condition because the child thread is not locking the mutex.
A barrier should do the trick nicely. Since you mention the need for support on Win32 in comments, barriers are supported on the latest Win32 pthreads, so you shouldn't have to write your own wrapper to get some portability between Win32 and *nix.
Something like:
typedef struct threaddata_ {
pthread_barrier_t* pbarrier;
} threaddata_t;
void* child_thread(void*arg) {
threaddata_t*x=(threaddata_t*)arg;
/* ... INITIALIZE ... */
int result = pthread_barrier_wait(x->pbarrier);
/* CHILD THREAD BODY */
return 0;
}
void start_thread(void) {
pthread_barrier_t barrier;
int result = pthread_barrier_init(&barrier, NULL, 2);
threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
x->pbarrier = &barrier;
int result=pthread_create(&threadid, 0, child_thread, &x);
result = pthread_barrier_wait(&barrier);
/* child has reached the barrier */
pthread_barrier_destroy(&barrier); /* note: the child thread should not use */
/* the barrier pointer after it returns from*/
/* pthread_barrier_wait() */
/* MAIN THREAD BODY */
}
The drawback to this solution is that it may needlessly blocks the child thread momentarily. If that's a problem, the condition variable solution mentioned by Dmitry Poroh is the way to go.
I need to see if a mutex is locked or unlocked in an if statement so I check it like this...
if(mutex[id] != 2){
/* do stuff */
}
but when I check it gcc gives me the following error:
error: invalid operands to binary != (have 'ptherad_mutex_t' and 'int')
So how can I check to see if the mutex is locked or not?
EDIT:
A key component to my problem is that my threads (by design) lock themselves right AFTER passing control to another thread. So when thread A passes control to thread B thread A is locked, thread B does some stuff, then when thread B is done it will unlock thread A.
The problem with this is that if thread B attempts to unlock thread A and thread A has not yet completed locking itself then the call to unlock is lost and thread A remains locked which causes a dead lock.
UPDATE:
I remade my program taking caf's suggestion but I am still running into problems. I have molded my program into the structure caf provided the best I can but I cannot even tell what is causing the dead lock now... I have created a new question here seeking help with my code.
Below is a runnable version of caf's suggestion. I made a small reordering in the function for thread a, without which both thread a and thread b would have been locked upon their creation, waiting for a condition that could never change.
#include <pthread.h>
int run_a = 0;
pthread_mutex_t lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_a = PTHREAD_COND_INITIALIZER;
int run_b = 0;
pthread_mutex_t lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_b = PTHREAD_COND_INITIALIZER;
void *a(void *);
void *b(void *);
int main(){
int status;
pthread_t thread_a;
pthread_t thread_b;
pthread_create(&thread_a, NULL, a, (void *)0);
pthread_create(&thread_b, NULL, b, (void *)0);
pthread_join(thread_a, (void **)&status);
pthread_join(thread_b, (void **)&status);
}
/* thread A */
void *a(void *i){
while (1) {
printf("thread A is running\n");
sleep(1);
/* unlock thread B */
pthread_mutex_lock(&lock_b);
run_b = 1;
pthread_cond_signal(&cond_b);
pthread_mutex_unlock(&lock_b);
/* wait for thread A to be runnable */
pthread_mutex_lock(&lock_a);
while (!run_a)
pthread_cond_wait(&cond_a, &lock_a);
run_a = 0;
pthread_mutex_unlock(&lock_a);
}
}
/* thread B */
void *b(void *i){
while (1) {
/* wait for thread B to be runnable */
pthread_mutex_lock(&lock_b);
while (!run_b)
pthread_cond_wait(&cond_b, &lock_b);
run_b = 0;
pthread_mutex_unlock(&lock_b);
printf("thread B is running\n");
sleep(1);
/* unlock thread A */
pthread_mutex_lock(&lock_a);
run_a = 1;
pthread_cond_signal(&cond_a);
pthread_mutex_unlock(&lock_a);
}
}
You can use pthread_mutex_trylock. If that succeeds, the mutex was unclaimed and you now own it (so you should release it and return "unheld", in your case). Otherwise, someone is holding it.
I have to stress though that "check to see if a mutex is unclaimed" is a very bad idea. There are inherent race conditions in this kind of thinking. If such a function tells you at time t that the lock is unheld, that says absolutely nothing about whether or not some other thread acquired the lock at t+1.
In case this is better illustrated with a code example, consider:
bool held = is_lock_held();
if (!held)
{
// What exactly can you conclude here? Pretty much nothing.
// It was unheld at some point in the past but it might be held
// by the time you got to this point, or by the time you do your
// next instruction...
}
Mutexes are not the right primitive for the scheme that you want to implement. You should be using condition variables:
int run_thread_a = 0;
pthread_mutex_t run_lock_a = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_a = PTHREAD_COND_INITIALIZER;
int run_thread_b = 0;
pthread_mutex_t run_lock_b = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t run_cond_b = PTHREAD_COND_INITIALIZER;
/* thread A */
while (1) {
/* Wait for Thread A to be runnable */
pthread_mutex_lock(&run_lock_a);
while (!run_thread_a)
pthread_cond_wait(&run_cond_a, &run_lock_a);
run_thread_a = 0;
pthread_mutex_unlock(&run_lock_a);
/* Do some work */
/* Now wake thread B */
pthread_mutex_lock(&run_lock_b);
run_thread_b = 1;
pthread_cond_signal(&run_cond_b);
pthread_mutex_unlock(&run_lock_b);
}
/* thread B */
while (1) {
/* Wait for Thread B to be runnable */
pthread_mutex_lock(&run_lock_b);
while (!run_thread_b)
pthread_cond_wait(&run_cond_b, &run_lock_b);
run_thread_b = 0;
pthread_mutex_unlock(&run_lock_b);
/* Do some work */
/* Now wake thread A */
pthread_mutex_lock(&run_lock_a);
run_thread_a = 1;
pthread_cond_signal(&run_cond_a);
pthread_mutex_unlock(&run_lock_a);
}
Each thread will block in pthread_cond_wait() until the other thread signals it to wake up. This will not deadlock.
It can easily be extended to many threads, by allocating one int, pthread_cond_t and pthread_mutex_t per thread.
You can't compare a pthread_mutex_t with a int.
You can use
int pthread_mutex_trylock(pthread_mutex_t *mutex);
to check that.