博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux多线程实践(2) --线程基本API
阅读量:6290 次
发布时间:2019-06-22

本文共 4819 字,大约阅读时间需要 16 分钟。

POSIX线程库

  与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”开头,要使用这些函数库,要通过引入头文<pthread.h>,而且链接这些线程函数库时要使用编译器命令的“-lpthread”选项[Ubuntu系列系统需要添加的是”-pthread”选项而不是”-lpthread”,如Ubuntu 14.04版本,深度Ubuntu等]

 

1.pthread_create

int pthread_create(pthread_t *restrict thread,		const pthread_attr_t *restrict attr,		void *(*start_routine)(void*), void *restrict arg);

创建一个新的线程

参数

  thread:线程ID

  attr:设置线程的属性,一般设置为NULL表示使用默认属性

  start_routine:是个函数地址,线程启动后要执行的函数

  arg:传给线程启动函数的参数

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

 

附-Posix错误检查

  UNIX传统的函数:成功返回0,失败返回-1,并且对设置全局变量errno以指定错误类型。然而pthreads函数出错时不会设置全局变量errno(而其他的大部分POSIX函数会设置errno)。而是将错误代码通过返回值返回;

  pthreads同样也提供了线程内的errno变量,对于每一个线程, 都有一个errno的值, 以支持其它使用errno的代码。对于pthreads函数的错误,建议通过返回值进行判定,因为读取返回值要比读取线程内的errno变量的开销更小!

/** 实践: 新的错误检查与错误退出函数 **/inline void err_check(const std::string &msg, int retno){    if (retno != 0)        err_exit(msg, retno);}inline void err_exit(const std::string &msg, int retno){    std::cerr << msg << ": " << strerror(retno) << endl;    exit(EXIT_FAILURE);}

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);

等待线程结束

  value_ptr:它指向一个指针,后者指向线程的返回值(用户获取线程的返回值)

/** 示例: 等待线程退出 **/void *thread_rotine(void *args){    for (int i = 0; i < 10; ++i)    {        printf("B");        fflush(stdout);        usleep(20);    }    pthread_exit(NULL);}int main(){    pthread_t thread;    int ret = pthread_create(&thread, NULL, thread_rotine, NULL);    err_check("pthread_create", ret);    for (int i = 0; i < 10; ++i)    {        printf("A");        fflush(stdout);        usleep(20);    }    ret = pthread_join(thread, NULL);    err_check("pthread_join", ret);    putchar('\n');    return 0;}

4.pthread_self

pthread_t pthread_self(void);

返回线程ID

/** 示例:主控线程与子线程传递数据 **/typedef struct _Student{    char name[20];    unsigned int age;} Student;void *threadFunction(void *args){    cout << "In Thread: " << pthread_self() << endl;    Student tmp = *(Student *)(args);    cout << "Name: " << tmp.name << endl;    cout << "Age: " << tmp.age << endl;    pthread_exit(NULL);}int main(){    Student student = {"xiaofang",22};    pthread_t thread;    //启动创建并启动线程    pthread_create(&thread,NULL,threadFunction,&student);    //等待线程结束    pthread_join(thread,NULL);    return 0;}

5.pthread_cancel

int pthread_cancel(pthread_t thread);

取消一个执行中的线程

6.pthread_detach

int pthread_detach(pthread_t thread);

  将一个线程分离-如果在新创建的线程结束时主线程没有结束同时也没有调用pthread_join,则会产生僵线程,次问题可以通过设置线程为分离的(detach)来解决;

 

总结:进程 VS. 线程

进程(pid_t)

线程(pthread_t)

Fork

Pthread_create

Waitpit

Pthread_join/Pthread_detach

Kill

Pthread_cancel

Pid

Pthead_self

Exit/return

Pthread_exit/return

僵尸进程(没有调用wait/waitpid等函数)

僵尸线程(没有调用pthread_join/pthread_detach)

/** 将并发echo server改造成多线程形式 注意线程竞速问题的解决**/void echo_server(int clientSocket);void *thread_routine(void *arg);int main(){    int sockfd = socket(AF_INET,SOCK_STREAM,0);    if (sockfd == -1)        err_exit("socket error");    int optval = 1;    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1)        err_exit("setsockopt error");    struct sockaddr_in serverAddr;    serverAddr.sin_family = AF_INET;    serverAddr.sin_port = htons(8002);    serverAddr.sin_addr.s_addr = INADDR_ANY;    //绑定本机的任意一个IP地址    if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)        err_exit("bind error");    if (listen(sockfd,SOMAXCONN) == -1)        err_exit("listen error");    while (true)    {        int peerSockfd = accept(sockfd, NULL, NULL);        if (peerSockfd == -1)            err_exit("accept error");        pthread_t tid;        /**注意: 下面这种用法可能会产生"竞速问题"                当另一个连接快读快速到达, peerSockfd的内容更改,                新创建的线程尚未将该值取走时,线程读取的就不是                我们想让线程读取的值了        int ret = pthread_create(&tid, NULL, thread_routine, (void *)&peerSockfd);        **/        //解决方案: 为每一个链接创建一块内存        int *p = new int(peerSockfd);        int ret = pthread_create(&tid, NULL, thread_routine, p);        if (ret != 0)            err_thread("pthread_create error", ret);    }    close(sockfd);}
void *thread_routine(void *args){    //将线程设置分离状态, 避免出现僵尸线程    pthread_detach(pthread_self());    int peerSockfd = *(int *)args;    //将值取到之后就将这块内存释放掉    delete (int *)args;    echo_server(peerSockfd);    cout << "thread " << pthread_self() << " exiting ..." << endl;    pthread_exit(NULL);}void echo_server(int clientSocket){    char buf[BUFSIZ] = {0};    int readBytes;    while ((readBytes = read(clientSocket, buf, sizeof(buf))) >= 0)    {        if (readBytes == 0)        {            cerr << "client connect closed" << endl;            break;        }        if (write(clientSocket, buf, readBytes) == -1)        {            cerr << "server thread write error" << endl;            break;        }        cout << buf;        bzero(buf, sizeof(buf));    }}

其完整源代码:

你可能感兴趣的文章
nodejs笔记1 ----关于express不是本地命令
查看>>
python debug
查看>>
docker-machine 远程安装docker
查看>>
最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
查看>>
3.2 进程间通信之fifo
查看>>
WEB 开发前传——js笔记
查看>>
C++多线程编程入门(转)
查看>>
C# to IL 6 Reference and Value Types(引用类型和值类型)
查看>>
Python 爬虫十六式 - 第七式:正则的艺术
查看>>
Android Studio的使用(五)--导入第三方Jar包
查看>>
PCL学习笔记(一)
查看>>
CoreGraphics相关方法
查看>>
Node Express 初探
查看>>
回溯法-求解装载问题(类似0-1背包)
查看>>
MATLAB中求矩阵非零元的坐标
查看>>
Tabular系列之问题1:如何利用其他人的账号进行权限测试?
查看>>
Configuration、SessionFactory、Session
查看>>
Sql Server基础小结
查看>>
轻装好上阵
查看>>
从国产浏览器更换到谷歌浏览器的心路历程
查看>>