I am creating an asynchronous chat application in C. I created two threads, one for receiving and another one for sending as follows.
void* send()
{
...
}
void* receive()
{
...
}
main()
{
..
inid = pthread_create(&incoming,NULL,receive,"Incoming thread");
outid= pthread_create(&outgoing,NULL,send,"Outgoing thread");
..
pthread_join(incoming,NULL);
pthread_join(outgoing,NULL);
..
}
What the problem is, the send and receive functions are called only once and the program terminates. I want both the threads to run forever till the user wishes to exit ( the condition to check for exit is defined in the send function). How to solve this?
One solution is to have a while(input != exit) type of loop in send.
And make your main to only wait for outgoing thread (which means having pthread_join only for outgoing thread). So, when the user chooses to exit, the main will exit without waiting for the incoming thread.
Secondly, you need to use a blocking receive function in the receive function. So, it is either processing an incoming message or waiting for one.
Another solution is to have a while(input != exit) type of loop in main. Have a message queue defined in which main can queue messages to be sent and the outgoing thread consumes messages from this thread to actually send them.
The outgoing thread is either sending a message or is blocked until the queue has a message in it to be sent.
The input thread behaves in the same way as described in the previous solution.
Related
I have this call in the cleanup of the main thread of process_B which receives messages on an IPC message queue:
if (msgctl(qId, IPC_RMID, NULL) < 0) {
perror("msgctl");
}
And when reached, reports the following:
msgctl : Invalid argument
Error: failed to remove message queue.
I have another process_A, which sends messages to process_B and isn't being shutdown.
Then there's this statement in man msgctl ...
IPC_RMID
Immediately remove the message queue, awakening all waiting
reader and writer processes (with an error return and errno set
to EIDRM). The calling process must have appropriate privileges
or its effective user ID must be either that of the creator or
owner of the message queue. The third argument to msgctl() is
ignored in this case.
I'm not clear on how removing the message queue awakens all readers and writers. Does process_A have to somehow close as well before process_B can remove the message queue?
If process_B closes, I'm trying to cleanup the resources to include this message queue. And if it is restarted, I'd like for process_B to "reconnect" to the message queue after having cleared the queue in the case that process_A was never shutdown. Is clearing the queue possible? And then of course I'd do the same for process_A.
Update: (adding the opening of the message queue):
key_t key = ftok(".", 'm');
int qid = msgget(key, IPC_CREAT | 0644);
if (qid == -1) {
perror("msgget");
return -1;
}
I have this call in the cleanup of the main thread of process_B which
receives messages on an IPC message queue:
if (msgctl(qId, IPC_RMID, NULL) < 0) {
perror("msgctl");
}
And when reached, reports the following:
msgctl : Invalid argument
Error: failed to remove message queue.
The "Error:" message must be from some other code not in evidence, but the "msgctl :" message appears to be output from perror(), reporting on an EINVAL. For an IPC_RMID command, that indicates that the queue ID passed to the function was invalid. Perhaps that queue had already been removed?
I'm not clear on how removing the message queue awakens all readers and writers. Does process_A have to somehow close as well before process_B can remove the message queue?
Removing the queue awakens all waiting readers and writers. That is, those that are currently blocked trying to send messages to the queue or receive messages from it. The docs are simply saying that those calls will stop blocking, and instead fail (returning -1) with errno set to EIDRM. So no, process_A does not have to terminate or perform any other action before process_B can remove the queue.
HOWEVER,
If process_B closes, I'm trying to cleanup the resources to include
this message queue.
Ok so far.
And if it is restarted, I'd like for process_B to
"reconnect" to the message queue after having cleared the queue in the
case that process_A was never shutdown.
I think you're not appreciating what it means to remove the queue. After successfully removing it, there is nothing left to reconnect to. You must instead create a new queue, and somehow get all processes involved to attach to and use that queue. It may well have a different queue ID (albeit obtained via the same key).
Is clearing the queue
possible? And then of course I'd do the same for process_A.
You can clear the queue without removing it by preventing all processes from sending new messages (via a process-shared mutex or semaphore) and then receiving all the available messages. Don't forget to provide for the mutex / semaphore to be released.
However, I urge you to think about your strategy here. If you simply clear the queue without removing it, then nothing prevents process_A from sending more messages to the queue while there is no process_B running, so
clearing the queue doesn't actually do much for resource usage, and
you need to think about what a new process_B will do with messages sent before it started execution.
Similar applies for the reverse direction.
Also, remember that System V message queues have kernel persistence, so their lifetime is not tied to that of any particular process. SysV MQs will live from their creation to their explicit removal, or until the system shuts down, whichever comes first.
I'm doing a project for university, a chat system with a server and multiple clients.
In the specification document there is written:
The main thread does a controlled loop on the global var go, and at each cycle waits for a connection request by an user
And also:
Server stops with SIGTERM or SIGINT. When signal is received, the global var go is set to zero, and all threads exit from the loop cycle
So, the thread main create the socket, bind the port and at every new connection does an accept() and create a thread worker which takes care of the communication with the client.
My problem is exiting the thread main only changing the global var.
In the thread main if I do
while (go && accept(params)) {}
it doesn't enter in the while loop.
So at the moment the code is
while (go) {
accept(params);
// Do stuff
}
And, well, when I set go to zero it waits on accept, so I have to create a new connection, it accepts the connection and then exit the thread 'cause go becomes zero.
Same problem with thread worker
while (go && read(socket_id, buffer, sizeof(char)) > 0) {}
It waits for a char from the socket to exit the loop.
I don't see a way to exit loops using only the go var.
I think I've to close the socket, or find another way, am I wrong?
I'm not interested in other ways to exit threads, just to know if it's possible to exit loops just changing the go var
Thanks!
Assuming you setup a signal handler for SIGINT and SIGTERM to toggle the go to !=0 you also want to unset the SA_RESTART flag for the handler(s), which would make accept() return -1 on the signal's reception.
To do so setup the signal handler using sigaction(). For the struct sigaction you pass in do not set the member sa_flags to hold SA_RESTART.
For a detailed description which system call is influenced by the SA_RESTART flag see section "Interruption of system calls and library functions by signal handlers" of man 7 signal.
Independendly from this make sure go is defined sig_atomic_t.
This is not any error in code, but to get an idea how to accomplish the following criteria. I have seen similar questions here and here, but did not get any particular way to do it.
Consider the following parts of code:
....
pthread_create(&Receiver,NULL,ReceiveFromServer,(void*)&ClientSoc);
sending =1;
while (sending)
{
SHOW_PROMPT;
gets(message);
memcpy(Packet.data,message,MAX_DATA_LENGTH);
if (SetCommand(&Packet,message) == CMD_EXT)
sending = 0;
send(ClientSoc,&Packet,PACKET_SIZE,0);
}
close(ClientSoc);
pthread_join(Receiver,NULL);
return 0;
....
And the ReceiveFromServer function:
void* ReceiveFromServer(void* ClientSoc)
{
int receiving =1;
int Status;
strPacket Packet;
while(receiving)
{
if(recv(*(int*)ClientSoc,&Packet,PACKET_SIZE,0)>0)
{
ParseReply(Packet);
SHOW_PROMPT;
}
if(GET_COMMAND(Packet.Header) == CMD_EXT)
receiving = 0;
}
return NULL;
}
Assume everything is declared or defined correctly.
So the thread terminates depending upon the received data from server, but the sender still loops as it do not know that the receiver is terminated. The sender only comes out of loop depending upon the user input (a particular word such as 'exit').How to notify the parent that the thread is terminating? I tried to make sending global and change it from inside the thread, but it didn't work.
Close the socket in the 'ReceiveFromServer' thread when you get the CMD_EXT. The sending thread should get the message soon enough - the send() call will return with an error.
In the main loop of the parent, replace:
while (sending)
with:
while (sending && pthread_kill(Receiver, 0) != ESRCH)
This will check the existence of the Receiver thread. See How do you query a pthread to see if it is still running? for more info.
Note, however, that How do I determine if a pthread is alive? emphasizes that you cannot do this for a detached thread. And http://man7.org/linux/man-pages/man3/pthread_kill.3.html states:
POSIX.1-2008 recommends that if an implementation detects the use of a thread ID after the end of its lifetime, pthread_kill() should return the error ESRCH. The glibc implementation returns this error in the cases where an invalid thread ID can be detected. But note also that POSIX says that an attempt to use a thread ID whose lifetime has ended produces undefined behavior, and an attempt to use an invalid thread ID in a call to pthread_kill() can, for example, cause a segmentation fault.
Closing the socket in the ReceiveFromServer thread when you get the CMD_EXT, would probably also work, as Are parallel calls to send/recv on the same socket valid? seems to indicate POSIX sockets are thread safe. But R. strongly recommends against it in Is closesocket thread safe?. And the RHEL5 Linux man 2 close states:
It is probably unwise to close file descriptors while they may be in use by system calls in other threads in the same process. Since a file descriptor may be re-used, there are some obscure race conditions that may cause unintended side effects.
When dealing with sockets, you have to be sure that there is no recv(2) still blocking on it on another thread, otherwise it might block forever, since no more messages will be sent via the socket. Be sure to use shutdown(2) to shut down all parts the connection before closing the socket.
Also, you'll probably also want to replace gets(message) with a non-blocking equivalent, to handle the case where the peer asynchronously sends a CMD_EXT while you are waiting for human input.
And of course you'll need to add socket error-handling, but that is beyond the scope of this question.
Maybe you could try to use pthread_tryjoin_np (I never used it) in the parent loop to detect if the thread has finished. It is only available for linux as I understood.
I am writing a basic user level thread library. The function prototype for thread creation is
thr_create (start_func_pointer,arg)
{
make_context(context_1,start_func)
}
start_func will be user defined and can change depending on user/program
once after creation of thread, if I start executing it using
swapcontext(context_1,context_2)
the function start_func would start running. Now , if a signal comes in , I need to handle it. Unfortunately, I just have the handle to start_func so I cant really define signal action inside the start_func
is there a way I can add a signal handling structure inside the start_function and point it to my code. something like this
thr_create (start_func_pointer,arg)
{
start_func.add_signal_hanlding_Structure = my_signal_handler();
make_context(context_1,start_func)
}
Does anybody know how posix does it ?
If you are talking about catching real signals from the actual operating system you are running on I believe that you are going to have to do this application wide and then pass the signals on down into each thread (more on this later). The problem with this is that it gets complicated if two (or more) of your threads are trying to use alarm which uses SIGALRM -- when the real signal happens you can catch it, but then who do you deliver it to (one or all of the threads?).
If you are talking about sending and catching signals just among the threads within a program using your library then sending a signal to a thread would cause it to be marked ready to run, even if it were waiting on something else previously, and then any signal handling functionality would be called from your thread resume code. If I remember from your previous questions you had a function called thread_yield which was called to allow the next thread to run. If this is the case then thread_yield needs to check a list of pending signals and preform their actions before returning to where ever thread_yield was called (unless one of the signal handlers involved killing the current thread, in which case you have to do something different).
As far as how to implement registering of signal handlers, in POSIX that is done by system calls made by the main function (either directly or indirectly). So you could have:
static int foo_flag = 0;
static void foo_handle(int sig) {
foo_flag = 1;
}
int start_func(void * arg) {
thread_sig_register(SIGFOO, foo_handle);
thread_pause();
// this is a function that you could write that would cause the current thread
// to mark itself as not ready to run and then call thread_yield, so that
// thread_pause() will return only after something else (a signal) causes the
// thread to become ready to run again.
if (foo_flag) {
printf("I got SIGFOO\n");
} else {
printf("I don't know what woke me up\n");
}
return 0;
}
Now, from another thread you can send this thread a SIGFOO (which is just a signal I made up for demonstration purposes).
Each of your thread control blocks (or whatever you are calling them) will have to have a signal handler table (or list, or something) and a pending signal list or a way to mark the signals as pending. The pending signals will be examined (possibly in some priority based order) and the handler action is done for each pending signal before returning to that threads normal code.
I have a simple server that looks something like this:
void *run_thread(void *arg) {
// Communicate via a blocking socket
}
int main() {
// Initialization happens here...
// Main event loop
while (1) {
new_client = accept(socket, ...);
pthread_create(&thread, NULL, &run_thread, *thread_data*);
pthread_detach(thread);
}
// Do cleanup stuff:
close(socket);
// Wait for existing threads to finish
exit(0);
)
Thus when a SIGINT or SIGTERM is received I need to break out of the main event loop to get to the clean up code. Moreover most likely the master thread is waiting on the accept() call so it's not able to check some other variable to see if it should break;.
Most of the advice I found was along the lines of this: http://devcry.blogspot.com/2009/05/pthreads-and-unix-signals.html (creating a special signal handling thread to catch all the signals and do processing on those). However, it's the processing portion that I can't really wrap my head around: how can I possibly tell the main thread to return from the accept() call and check on an external variable to see if it should break;?
Usually I am waiting on select(listeninig-socket-here) not on accept(). accept() is usually a method where a program doesn't spend lots of time waiting. And when I wait in select() and the signal SIGTERM is sent to that thread (in your case it is the main thread) I exit from that select and select returns interrupted system call .
I second skwllsp in his opinion that you should be using select call instead of accept. But, my additional suggestion is that you follow the advice of the blog whose link you have posted and create a seperate signal handling thread and ignore signals in all other threads. Then when the signal is received in the signal handling thread, use pthread_cancel to cancel the other threads. When you use pthread_cancel, if the thread which is being cancelled is in cancellation point (select happens to be one), it will come out and enter into your handler and you can cleanup and exit the thread.
You can find more info on this here, here and here