Linux多线程实践(2) --线程基本API

来源:互联网 发布:中国债务危机 知乎 编辑:程序博客网 时间:2024/06/06 05:05

POSIX线程库

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

 

1.pthread_create

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int pthread_create(pthread_t *restrict thread,  
  2.         const pthread_attr_t *restrict attr,  
  3.         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变量的开销更小!

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 实践: 新的错误检查与错误退出函数 **/  
  2. inline void err_check(const std::string &msg, int retno)  
  3. {  
  4.     if (retno != 0)  
  5.         err_exit(msg, retno);  
  6. }  
  7. inline void err_exit(const std::string &msg, int retno)  
  8. {  
  9.     std::cerr << msg << ": " << strerror(retno) << endl;  
  10.     exit(EXIT_FAILURE);  
  11. }  

2.pthread_exit

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void pthread_exit(void *value_ptr);  

线程终止

  value_ptr:指向该线程的返回值;注意:value_ptr不能指向一个局部变量

 

3.pthread_join

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int pthread_join(pthread_t threadvoid **value_ptr);  

等待线程结束

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

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 示例: 等待线程退出 **/  
  2. void *thread_rotine(void *args)  
  3. {  
  4.     for (int i = 0; i < 10; ++i)  
  5.     {  
  6.         printf("B");  
  7.         fflush(stdout);  
  8.         usleep(20);  
  9.     }  
  10.     pthread_exit(NULL);  
  11. }  
  12.   
  13. int main()  
  14. {  
  15.     pthread_t thread;  
  16.     int ret = pthread_create(&thread, NULL, thread_rotine, NULL);  
  17.     err_check("pthread_create", ret);  
  18.   
  19.   
  20.     for (int i = 0; i < 10; ++i)  
  21.     {  
  22.         printf("A");  
  23.         fflush(stdout);  
  24.         usleep(20);  
  25.     }  
  26.   
  27.     ret = pthread_join(thread, NULL);  
  28.     err_check("pthread_join", ret);  
  29.     putchar('\n');  
  30.     return 0;  
  31. }  

4.pthread_self

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. pthread_t pthread_self(void);  

返回线程ID

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 示例:主控线程与子线程传递数据 **/  
  2. typedef struct _Student  
  3. {  
  4.     char name[20];  
  5.     unsigned int age;  
  6. } Student;  
  7.   
  8. void *threadFunction(void *args)  
  9. {  
  10.     cout << "In Thread: " << pthread_self() << endl;  
  11.     Student tmp = *(Student *)(args);  
  12.     cout << "Name: " << tmp.name << endl;  
  13.     cout << "Age: " << tmp.age << endl;  
  14.   
  15.     pthread_exit(NULL);  
  16. }  
  17.   
  18. int main()  
  19. {  
  20.     Student student = {"xiaofang",22};  
  21.   
  22.     pthread_t thread;  
  23.     //启动创建并启动线程  
  24.     pthread_create(&thread,NULL,threadFunction,&student);  
  25.     //等待线程结束  
  26.     pthread_join(thread,NULL);  
  27.   
  28.     return 0;  
  29. }  


5.pthread_cancel

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int pthread_cancel(pthread_t thread);  

取消一个执行中的线程


6.pthread_detach

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 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)

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 将并发echo server改造成多线程形式  
  2. 注意线程竞速问题的解决 
  3. **/  
  4. void echo_server(int clientSocket);  
  5. void *thread_routine(void *arg);  
  6. int main()  
  7. {  
  8.     int sockfd = socket(AF_INET,SOCK_STREAM,0);  
  9.     if (sockfd == -1)  
  10.         err_exit("socket error");  
  11.   
  12.     int optval = 1;  
  13.     if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1)  
  14.         err_exit("setsockopt error");  
  15.   
  16.     struct sockaddr_in serverAddr;  
  17.     serverAddr.sin_family = AF_INET;  
  18.     serverAddr.sin_port = htons(8002);  
  19.     serverAddr.sin_addr.s_addr = INADDR_ANY;    //绑定本机的任意一个IP地址  
  20.     if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)  
  21.         err_exit("bind error");  
  22.   
  23.     if (listen(sockfd,SOMAXCONN) == -1)  
  24.         err_exit("listen error");  
  25.   
  26.     while (true)  
  27.     {  
  28.         int peerSockfd = accept(sockfd, NULL, NULL);  
  29.         if (peerSockfd == -1)  
  30.             err_exit("accept error");  
  31.   
  32.         pthread_t tid;  
  33.         /**注意: 下面这种用法可能会产生"竞速问题" 
  34.                 当另一个连接快读快速到达, peerSockfd的内容更改, 
  35.                 新创建的线程尚未将该值取走时,线程读取的就不是 
  36.                 我们想让线程读取的值了 
  37.         int ret = pthread_create(&tid, NULL, thread_routine, (void *)&peerSockfd); 
  38.         **/  
  39.         //解决方案: 为每一个链接创建一块内存  
  40.         int *p = new int(peerSockfd);  
  41.         int ret = pthread_create(&tid, NULL, thread_routine, p);  
  42.         if (ret != 0)  
  43.             err_thread("pthread_create error", ret);  
  44.     }  
  45.     close(sockfd);  
  46. }  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void *thread_routine(void *args)  
  2. {  
  3.     //将线程设置分离状态, 避免出现僵尸线程  
  4.     pthread_detach(pthread_self());  
  5.     int peerSockfd = *(int *)args;  
  6.     //将值取到之后就将这块内存释放掉  
  7.     delete (int *)args;  
  8.   
  9.     echo_server(peerSockfd);  
  10.     cout << "thread " << pthread_self() << " exiting ..." << endl;  
  11.     pthread_exit(NULL);  
  12. }  
  13. void echo_server(int clientSocket)  
  14. {  
  15.     char buf[BUFSIZ] = {0};  
  16.     int readBytes;  
  17.     while ((readBytes = read(clientSocket, buf, sizeof(buf))) >= 0)  
  18.     {  
  19.         if (readBytes == 0)  
  20.         {  
  21.             cerr << "client connect closed" << endl;  
  22.             break;  
  23.         }  
  24.         if (write(clientSocket, buf, readBytes) == -1)  
  25.         {  
  26.             cerr << "server thread write error" << endl;  
  27.             break;  
  28.         }  
  29.         cout << buf;  
  30.         bzero(buf, sizeof(buf));  
  31.     }  
  32. }  

其完整源代码:download.csdn.net/detail/hanqing280441589/8440763

0 0