I am expecting to get 100,000 requests at least 100 of them would be concurrent. Each time I get a request, I am creating a new thread and destroy it once it's done using pthread_exit(). Using pthread_detach I am getting 99% success rate. Is there a better way than this?
pthread_t hilo;
// infinite loop
while ((client_sock = accept(server_sock, (struct sockaddr *) &client_sockaddr, &len))) {
struct ClientSocket socks;
// some code...
pthread_create(&hilo, NULL, func, &socks);
pthread_detach(hilo);
printf("\nSocket is listening for the next request...\n");
}
I heard pthread_join would be a better way to utilize resources without reaching the thread limit, but the way I am doing it is not concurrent.
pthread_t hilo;
// infinite loop
while ((client_sock = accept(server_sock, (struct sockaddr *) &client_sockaddr, &len))) {
struct ClientSocket socks;
// some code...
pthread_create(&hilo, NULL, func, &socks);
pthread_join(hilo, NULL); // it stops the main thread
printf("\nSocket is listening for the next request...\n");
}
Any ideas would be appreciated!
Each time I get a request, I am creating a new thread and destroy it once it's done
Don't: it's not a smart thing to do, because thread creation is a heavy-weight operation.
I heard pthread_join would be a better way to utilize resources without reaching the thread limit, but the way I am doing it is not concurrent.
Correct. Whenever you see someone doing pthread_create immediately followed by pthread_join, you can tell that they have no idea what they are doing. The exact same result could be achieved (much more efficiently) by simply calling func directly.
Any ideas would be appreciated!
You need a producer-consumer queue. The listening thread will accept connections and enqueue them for other threads in a (size-limited) thread pool. The other threads will dequeue one item of work, and perform func on that item. Then go back for next item, and so on.
Here is an example producer/consumer implementation. But you can find many others with "producer consumer queue" search.
Related
I wrote a small tcp server, which creates a new thread for each incoming connection:
while (server_running)
{
client_sock = accept(server_sock,
(struct sockaddr *)&client_name,
&client_name_len);
if(!server_running)
break;
if (client_sock == -1)
continue;
/* accept_request(client_sock); */
if (pthread_create(&newthread , NULL, &accept_request, &client_sock) != 0)
perror("pthread_create");
}
After about 380 successfull connections, the error message
'pthread_create:cannot allocate memory'
occurs on every new connection attempt. I really don't have a clue where this comes from, since accept_request runs properly. I also noticed that there are many connections with status TIME_WAIT during the run (I used netstat for this). So where could something be going wrong?
When your thread exits, it still hangs around in memory. By default a thread on linux consumes 8 or 10MB of stack, so with 380 threads, you might use nearly 4GB of virtual memory - which might hit a limit on your system.
To have a thread be disposed when it is finished executing , you need to call pthread_join() on that thread, or you can make the thread a 'detached' thread. A detached thread will automatically be disposed when it ends execution. You can add
pthread_detach(pthread_self());
to the start of your accept_request() thread function to make it a detached thread.
As a side note, you have a race condition on the call to
pthread_create(&newthread , NULL, &accept_request, &client_sock)
Here you pass &client_sock to the thread, a local variable. If you have 2 clients connecting to your server at almost the same time, the last one will overwrite the client_sock variable, and 2 of your threads will see the same file descriptor. You could e.g. rather do this:
int *new_fd = malloc(sizeof *new_fd);
*new_fd = client_sock;
pthread_create(&newthread , NULL, &accept_request, new_fd)
And make sure your accept_request thread free()'s the passed in argument.
I am trying to implement a multithreaded UDP server by creating thread.
The following method is used for creating thread.
pthread_create(&threadID, NULL, ThreadMain, threadArgs);
ThreadMain method is,
void *ThreadMain(void *threadArgs) {
pthread_detach(pthread_self());
int sock = ((struct ThreadArgs *) threadArgs)->sock;
free(threadArgs);
HandleUDPClient(sock);
return (NULL);
}
In the HandleUDPClient method is like this,
void HandleUDPClient(int sock) {
struct sockaddr_storage clntAddr; // Client address
// Set Length of client address structure (in-out parameter)
socklen_t clntAddrLen = sizeof(clntAddr);
// Block until receive message from a client
char buffer[MAXSTRINGLENGTH]; // I/O buffer
// Size of received message
ssize_t numBytesRcvd = recvfrom(sock, buffer, MAXSTRINGLENGTH, 0, (struct sockaddr *) &clntAddr, &clntAddrLen);
...
...
When I am creating socket and running the HandleUDPClient method it handles requests from client perfectly. But when I am trying to use thread, after entering the HandleUDPClient method it does not process the recvfrom method. Actually it does not wait for the client to receive any request. Program just terminates.
Can anybody tell me why this problem occurring and how can I resolve it?
The problem is that you detach your threads, meaning that you will not have to wait for your threads to exit. Instead the main program continues its work, until it reaches its end and then exit, with no regard for the (detached) threads still running.
Either don't detach the threads, and use pthread_join to "join" the threads, or use pthread_exit from the main thread to make sure it will wait for all detached threads to finish.
I'm trying to grasp the concepts of multithreading programming, and I think I'm doing well, but then I've found the following code for a simple echo server:
http://www.cs.utah.edu/~swalton/listings/sockets/programs/part2/chap7/echo-thread.c
And I'm thinking that the code is wrong, because it uses the same main local variable to store the data socket for each incoming connection. In particular, Im concerned about this part of main():
while (1)
{ int client, addr_size = sizeof(addr);
pthread_t child;
client = accept(sd, (struct sockaddr*)&addr, &addr_size);
printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if ( pthread_create(&child, NULL, Child, &client) != 0 )
perror("Thread creation");
else
pthread_detach(child); /* disassociate from parent */
}
As far as I understand, the variable client, local to the while loop, is allocated at exactly the same address in each iteration of the loop. So, when the first client is accepted, the thread receives &client, and when the second client is accepted, the value of client is overwritten with the new data socket, and this can have side-effects in the thread which is already running on the first client.
Observing the code of the function Child, which is the service thread, I can see that the argument is copied into a local variable:
void* Child(void* arg)
{ char line[100];
int bytes_read;
int client = *(int *)arg;
...etc...
and probably the author thought that this copy allows him to later tamper with the main client variable, but IMHO this can cause a race condition. If a second client arrives while the first thread is copying this variable, the value copied can be corrupt.
Am I right?
Yes, you are correct. There are two obvious ways to fix this:
Pass client to the thread instead of &client.
Allocate a new integer on the heap and pass its address to the thread and let the thread free it when it's done with it.
Yes, you are right.
You can demonstrate that you're right by adding a long sleep before int client = *(int*)arg; and connecting to the server two times while the first client thread.
i have a problem with a multi-thread SMTP/POP3 server. The server starts a pool of threads to handle incoming connections. The main thread create the sockets and the the threads, passing the sockets as parameters in a proper structure. The loop function for the threads is the following:
SOCKET SMTP_ListenSocket = (SOCKET) data->SMTPconn;
SOCKET POP3_ListenSocket = (SOCKET) data->POP3conn;
static struct sockaddr_in ClntAddr;
unsigned int clntLen = sizeof(ClntAddr);
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
hEvents[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
hEvents[2] = exitEvent; //HANDLE FOR A MANUAL RESET EVENT
WSAEventSelect(SMTP_ListenSocket, hEvents[0], FD_ACCEPT);
WSAEventSelect(POP3_ListenSocket, hEvents[1], FD_ACCEPT);
while(1){
DWORD res = WaitForMultipleObjects(3, hEvents, FALSE, INFINITE);
switch(res){
case WAIT_OBJECT_0: {
ClientSocket = my_accept(SMTP_ListenSocket,(struct sockaddr *) &ClntAddr,&clntLen);
/* ... */
my_shutdown(ClientSocket,2);
my_closesocket(ClientSocket);
ClientSocket = INVALID_SOCKET;
break;
}
case WAIT_OBJECT_0 + 1: {
ClientSocket = my_accept(POP3_ListenSocket,(struct sockaddr *) &ClntAddr,&clntLen);
/* ... */
my_shutdown(ClientSocket,2);
my_closesocket(ClientSocket);
ClientSocket = INVALID_SOCKET;
break;
}
case WAIT_OBJECT_0 + 2:
{
exitHandler(0);
break;
}
}//end switch
}//end while
When the pool contains only one thread there's no problem. When the pool consist of more threads, only one thread accepts the incoming connections
Do you have the pooled threads all calling this same code? If so, then don't use WaitForMultipleObjects() (or WSAWaitForMultipleEvents()) like this. This kind of model only works reliably if one thread is polling connections. If you have multiple threads polling at the same time, then you have race conditions.
Instead, you should use AcceptEx() with Overlapped I/O or Completion Ports instead. The thread that creates the sockets can call AcceptEx() on each socket to queue a new operation on each one, then the pooled threads can use GetQueuedCompletionStatus() or GetOverlappedResult() to dequeue a pending connection without worrying about trampling on other threads. Once a connection is accepted, the receiving thread can process it as needed and then call AcceptEx() to queue a new operation for that socket.
Each thread here is setting a new WSAEventSelect prior to entering the wait. This overwrites any existing event selects. This means that, once a thread (call it thread A) accepts a connection, there is no event associated with the socket.
To solve this, you should call WSAEventSelect again within your switch, immediately after the accept(). This will restore the event binding immediately before going into any potentially lengthy processing.
Note that it's possible that two threads may be awoken for the same event, if the timing works out just right. You can hack around that by going back to your wait loop if the accept fails, but this is a bit unsatisfying.
So, instead of rolling your own version, use IO completion ports here. I/O completion ports have a number of additional features, and avoid potential race conditions in which two threads might pick up the same event. They also take steps to reduce context switches when your code is not CPU bound.
I am new to both sockets and threads. I have this code:
listen(socket_fd, 20);
/* Looooop */
while (1) {
newsocket_fd = accept(socket_fd,
(struct sockaddr *) &client_addr,
&client_len);
if (newsocket_fd < 0) {
error("ERROR on accept");
}
pthread_t thread;
pthread_create(&thread, NULL, run_thread, (void *) newsocket_fd);
pthread_join(thread, NULL);
}
How can I start a new thread for each new connection, rather than for each request? These threads should be started when a new connection comes in, and these threads should then wait for requests, handle those requests, and finally return when the connection is closed. There should be one thread for each connection. Here is the code for run_thread:
void
*run_thread(void *ptr) {
char buffer[256];
bzero(buffer, 256);
int n;
n = read((int) ptr, buffer, 255);
if (n < 0) error("ERROR Reading from socket");
printf("%s\n\n**********\n\n", buffer);
/* Parse buffer and return result */
char *result;
{
/* First, determine command, 4 characters */
/* (much code) */
}
n = write((int) ptr, result, strlen(result));
if (n < 0) error("ERROR Writing to socket");
}
Can anyone help me? Thanks.
There is also a different critical error.
You cast the int to (void*). This does not make sense. Also, you can't pass the address directly since the variable could be changed on the next accept() call before the thread can copy the variable to its local stack. One way to write it would be something like this:
while (1) {
newsocket_fd = accept(socket_fd,
(struct sockaddr *) &client_addr,
&client_len);
if (newsocket_fd < 0) {
error("ERROR on accept");
}
pthread_t thread;
int *newsock = malloc(sizeof(int));
*newsock = newsocket_fd;
pthread_create(&thread, NULL, run_thread, newsock);
pthread_detach(thread);
}
With this approach, the thread will make sure to free() the newsock. E.g a simple
void *handler(void *thread_data) {
int fd = *(int *) thread_data;
free(thread_data);
....
}
Also, I assume pthread_detach() is okay, if the main program doesn't care about syncing up with the thread later with pthread_join().
You almost got it right. The problem is, however, that you are joining the thread right after creation, and pthread_join is actually a blocking call which is waiting for the thread to finish. It means that you will not be able to accept any more connections while that one thread is running. To solve this problem, you might want to use detached threads. You don't have to join detached threads. For this purpose, you have to create thread attributes using pthread_attr_init function and pass those attributes to pthread_create.
Be aware that if you have too many client connections, your application may run out of resources. So, in real world, you have to manage a pool of threads. But the best case scenario for TCP/IP server applications is to use asynchronous I/O. I do not know about C, but there is a very good library in C++ for asynchronous I/O application called boost::asio.
Vlad has good advice.
Also note that your newsocket_fd variable is being reused for each new connection in your accept loop, and then a pointer to it is passed to every worker thread. This will cause problems when you start having multiple clients connected at the same time.
EDIT: Ignore this comment, I misread the mistake you were making. Others have given proper corrections for your handling of newsocket_fd.