1.多线程基础知识
线程是进程的一条执行路径,线程在Unix系统下,通常被称为轻量级的进程。所有的线程都是在同一进程空间运行,这也意味着多条线程将共享该进程中的全部系统资 源,如虚拟地址空间,文件描述符和信号处理等等。一个进程可以有很多线程,每条线程并行执行不同的任 务。
一个进程创建后,会首先生成一个缺省的线程,通常称这个线程为主线程(或称控制线程)。主线程就是通过main函数进入的线程,由主线程调用pthread_create()创建的线程称为子线程。
主线程和子线程的默认关系是:无论子线程执行完毕与否,一旦主线程执行完毕退出,所有 子线程执行都会终止。
主线程和子线程通常定义以下两种关系:
可会合:这种关系下,主线程需要明确执行等待操作,在子线程结束后,主线程的等待操作执行完毕,子线 程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。主线程必须会合可会合的子线程。在主线程的线程函 数内部调用子线程对象的wait函数实现,即使子线程能够在主线程之前执行完毕,进入终止态,也必须执行会合操作,否 则,系统永远不会主动销毁线程,分配给该线程的系统资源也永远不会释放。
相分离:表示子线程无需和主线程会合,也就是相分离的,这种情况下,子线程一旦进入终止状态,这种 方式常用在线程数较多的情况下,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是 很困难或不可能的,所以在并发子线程较多的情况下,这种方式也会经常使用。
线程的分离状态决定一个线程以什么样的方式来终止自己,在默认的情况下,线程是非分离状态的,这种情况下,原有的线程 等待创建的线程结束,只有当pthread_join()函数返回时,创建的线程才算终止,释放自己占用的系统资源,而分离线程没有被其 他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
2.实现函数
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
typedef struct
{
int detachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
}pthread_attr_t;
3.实现代码
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>
#include <pthread.h>
#include <ctype.h>
#define MSG_STR "Hello, you have connected to the server successfully!\n"
typedef void *(THREAD_BODY)(void *thread_arg);
void *thread_worker(void *ctx);
int thread_start(pthread_t *thread_id, THREAD_BODY *thread_workbody, void *thread_arg);
void *thread_worker(void *ctx)
{
int client_fd;
int rv;
char buf[1024];
int i;
if( !ctx )
{
printf("ERROR: invalid input argments!\n");
pthread_exit(NULL);
}
client_fd = (int)ctx;
while(1)
{
memset(buf, 0, sizeof(buf));
rv=read(client_fd, buf, sizeof(buf));
if( rv < 0)
{
printf("Read data from client[%d] unsuccessfully: %s and thread will exit\n", client_fd, strerror(errno));
close(client_fd);
pthread_exit(NULL);
}
else if( rv == 0)
{
printf("Socket[%d] get disconnected and thread will exit.\n", client_fd); close(client_fd);
pthread_exit(NULL);
}
else if( rv > 0 )
{
printf("Read %d bytes data from Server: %s\n", rv, buf);
}
rv=write(client_fd, MSG_STR, strlen(MSG_STR));
if(rv < 0)
{
printf("Write to client by sockfd[%d] failure: %s and thread will exit\n", client_fd, strerror(errno));
close(client_fd);
pthread_exit(NULL);
}
}
}
int thread_start(pthread_t *thread_id, THREAD_BODY *thread_workbody, void *thread_arg)
{
pthread_attr_t thread_attr;
if( pthread_attr_init(&thread_attr) )
{
printf("pthread_attr_init() failure: %s\n", strerror(errno));
return -1;
}
if( pthread_attr_setstacksize(&thread_attr, 120*1024) )
{
printf("pthread_attr_setstacksize() failure: %s\n", strerror(errno));
return -2;
}
if( pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) )
{
printf("pthread_attr_setdetachstate() failure: %s\n", strerror(errno));
return -3;
}
if( pthread_create(thread_id, &thread_attr, thread_workbody, thread_arg) )
{
printf("Create thread failure: %s\n", strerror(errno));
return -4;
}
return 0;
}
int main(int argc, char **argv)
{
int server_fd = -1, client_fd = -1;
int rv = -1;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t len;
int port = 8889;
int on = 1;
pthread_t tid;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_fd < 0)
{
printf("Create socket unsuccessfully: %s\n", strerror(errno));
return -1;
}
printf("Create socket[%d] successfully!\n", server_fd);
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
rv=bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(rv < 0)
{
printf("Socket[%d] bind on port[%d] failure: %s\n", server_fd, port, strerror(errno));
return -2;
}
listen(server_fd, 10);
while(1)
{
client_fd=accept(server_fd, (struct sockaddr *)&client_addr, &len);
if(client_fd < 0)
{
printf("Accept new client failure: %s\n", strerror(errno));
continue;
}
printf("Accept new client[%s:%d] successfully\n\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
thread_start(&tid, thread_worker, (void *)client_fd);
}
close(server_fd);
return 0;
}