POSIX 线程(一)

一. POSIX线程先关函数
POSIX线程库
    与线程有关的函数构成一个完整的系列,绝大多数函数的名字都是以"pthread"打头的
    要使用这些函数库,引入头文件<pthread.h>
    连接这些线程函数库时要使用编译器命令的"-lpthread"选项


1. pthread_create函数
功能:创建一个新的线程
原型: int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

参数:
    thread: 返回线程ID
    attr: 设置线程的属性, attr为NULL 表示使用默认属性
    start_routine: 是个函数地址,线程启动后要执行这个函数
    arg : 传给线程启动后函数的参数
返回值:  成功返回0; 失败返回错误码  

错误检查
    (1) 传统一些函数是,成功返回0, 失败返回-1, 并且对全局变量 errno赋值以指示错误.
    (2) pthreads 函数出错时不会设置全局变量 errno(而大部分其他POSIX函数会这样做).而是将错误代码通过返回值返回.
    (3) pthreads 同样也提供了线程内的errno 变量,以支持其他使用 errno 的代码.对于 pthreads 函数的错误,建议通过返回值判定,因为读取返回值要比读取线程内的 errno 变量的开销更小
.
    
2. pthread_exit 函数
功能: 线程终止
原型:
    void pthread_exit(void * value_ptr);
参数:
    value_ptr: value_ptr 不要指向一个局部变量.
返回值: 无返回值,和进程一样,线程结束的时候无法返回到它的调用者(自身)

3. pthread_join 函数
功能:等待线程结束
原型:
    int pthread_join(pthread_t thread,void ** value_ptr);
参数:
    thread: 线程ID
    value_ptr : 它指向一个指针,后者指向线程的返回值
返回值: 成功返回0,失败返回错误码.

3. pthread_self 函数
功能: 返回线程ID
原型: pthread_t  pthread_self(void);
返回值: 成功返回0

4. pthread_cancel 函数
功能: 取消一个执行中的线程
原型:
    int pthread_cancel(pthread_t  thread);
参数:
    thread: 线程ID
返回值: 成功返回0, 失败返回错误码

5. pthread_detach 函数
功能: 将一个线程分离
原型:
    int  pthread_detach(pthread_t thread);
参数:
    thread: 线程ID

返回值: 成功返回0, 失败返回错误码


案例代码:

pthread.c

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) 	do 	{ 		perror(m); 		exit(EXIT_FAILURE); 	}while(0)
	
	

void* thread_routine(void *arg)
{
	int i;
	for(i=0;i<20;i++)
	{
		printf(" B ");
		fflush(stdout);
		usleep(20);
		
		if(i==3)
			pthread_exit("when i==3, pthread exit ");
	}
	sleep(3);  //延迟子线程的结束 
	return 0;
}

int main()
{
	pthread_t tid;
	int ret;
	// 错误信息通过函数返回
	if ( (ret = pthread_create(&tid,NULL,thread_routine,NULL)) !=0 ) 
	{
	 	fprintf(stderr,"pthread_create:%s\n",strerror(ret));
	 	exit(EXIT_FAILURE);
	}
	int i;   /// 为主线程,打印字母 A 
	for(i=0;i<20;++i)
	{
		printf(" A ");
		fflush(stdout);	// 刷新输出缓冲区
		usleep(20);
	}
	
	// 等待子线程的结束 
	void *value;
	if( (ret = pthread_join(tid,&value)) != 0)
	{
		fprintf(stderr,"pthread_create:%s\n",strerror(ret));
		exit(EXIT_FAILURE);
	}
	printf("\n");
	printf("return message: %s\n",(char*)value);
	return 0;
}

技术分享

二. 用线程实现回射客户/服务器程序

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m)         do         {                 perror(m);                 exit(EXIT_FAILURE);         } while(0)

void echo_srv(int conn)
{
    char recvbuf[1024];
    while (1)
    {
        memset(recvbuf, 0, sizeof(recvbuf));
        int ret = read(conn, recvbuf, sizeof(recvbuf));
        if (ret == 0)
        {
            printf("client close\n");
            break;
        }
        else if (ret == -1)
            ERR_EXIT("read");
        fputs(recvbuf, stdout);
        write(conn, recvbuf, ret);
    }
   close(conn);
}

void *thread_routine(void *arg)
{
     // 主线程没有调用pthread_join等待线程退出
     //剥离线程,避免产生僵线程    int conn = (int)arg;
     // pthread_self 返回线程ID
     // pthread_detach 分离线程
    pthread_detach(pthread_self());
    int conn = *((int *)arg);  // 将无类型指针强制转换成int* 指针
    free(arg); // 取完值,free掉
    echo_srv(conn); //每个线程处理一个连接,同一个进程没有可监听套接字
    printf("exiting thread ...\n");
    return NULL;
}

int main(void)
{
    int listenfd;
    if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        ERR_EXIT("socket");

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(5188);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    int on = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
        ERR_EXIT("setsockopt");

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("bind");
    if (listen(listenfd, SOMAXCONN) < 0)
        ERR_EXIT("listen");

    struct sockaddr_in peeraddr;
    socklen_t peerlen = sizeof(peeraddr);
    int conn;

    while (1)
    {
        if ((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0)
            ERR_EXIT("accept");

        printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

        pthread_t tid;
        //int ret;  /*pthread_create(&tid, NULL, thread_routine, (void*)&conn);*/
        // race condition问题,竟态问题        
        int *p = malloc(sizeof(int));
        *p = conn;
        int ret;
        if ((ret = pthread_create(&tid, NULL, thread_routine,p)) != 0) 
        //64位系统时指针不是4个字节,不可移植 , 所有使用malloc,               
        {   
        	fprintf(stderr, "pthread_create:%s\n", strerror(ret));                     
            exit(EXIT_FAILURE);                
        }    
    }
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。