主页
  • 主页
  • 分类
  • 热文
  • 教程
  • 面试
  • 标签
C++

C++ 基础

C++ 主页
C++ 概述
C++ 环境
C++ 基本语法
C++ 注释
C++ 数据类型
C++ Hello, World
C++ 省略命名空间
C++ 数值类型
C++ 字符类型
C++ 布尔类型
C++ 变量
C++ 作用域
C++ 多个变量
C++ 输入输出基础
C++ 常量/文字
C++ 修饰符类型
C++ 存储类别
C++ 操作符
C++ 决策结构
C++ 循环结构
C++ foreach 循环
C++ 数字
C++ 数组
C++ 指针
C++ 枚举类型
C++ 引用变量
C++ 日期与时间
C++ 结构体
C++ 联合类型

C++ 字符串

C++ 字符串
C++ 字符串长度
C++ 字符串连接

C++ 函数

C++ 函数
C++ 多参数函数
C++ 递归
C++ return 语句
C++ 函数重载
C++ 函数重写

C++ 面向对象

C++ 面向对象
C++ 类和对象
C++ 多重继承
C++ 多层次继承
C++ 继承
C++ 重载
C++ 多态性
C++ 抽象
C++ 封装
C++ 接口

C++ 高级

C++ 文件和流
C++ 异常处理
C++ 动态内存
C++ 命名空间
C++ 模板
C++ 预处理器
C++ 信号量
C++ 多线程
C++ Web 编程
C++ 高级概念

基础

C++ 主页
C++ 概述
C++ 环境
C++ 基本语法
C++ 注释
C++ 数据类型
C++ Hello, World
C++ 省略命名空间
C++ 数值类型
C++ 字符类型
C++ 布尔类型
C++ 变量
C++ 作用域
C++ 多个变量
C++ 输入输出基础
C++ 常量/文字
C++ 修饰符类型
C++ 存储类别
C++ 操作符
C++ 决策结构
C++ 循环结构
C++ foreach 循环
C++ 数字
C++ 数组
C++ 指针
C++ 枚举类型
C++ 引用变量
C++ 日期与时间
C++ 结构体
C++ 联合类型

字符串

C++ 字符串
C++ 字符串长度
C++ 字符串连接

函数

C++ 函数
C++ 多参数函数
C++ 递归
C++ return 语句
C++ 函数重载
C++ 函数重写

面向对象

C++ 面向对象
C++ 类和对象
C++ 多重继承
C++ 多层次继承
C++ 继承
C++ 重载
C++ 多态性
C++ 抽象
C++ 封装
C++ 接口

高级

C++ 文件和流
C++ 异常处理
C++ 动态内存
C++ 命名空间
C++ 模板
C++ 预处理器
C++ 信号量
C++ 多线程
C++ Web 编程
C++ 高级概念

C++ 多线程


上一章 下一章

多线程是一种特殊的多任务形式,而多任务是指计算机能够同时运行两个或更多的程序的能力。通常,有两种类型的多任务:基于进程的和基于线程的。

基于进程的多任务处理程序的同时执行。基于线程的多任务处理同一程序的不同部分的同时执行。

一个多线程程序包含两个或更多的可以并发执行的部分。这种程序的每一部分被称为一个线程,每一个线程定义了一个单独的执行路径。

在 C++11 之前,没有内置的支持多线程应用的功能。相反,它完全依赖于操作系统提供此功能。

本教程假设你正在使用 Linux 操作系统,并且我们将使用 POSIX 来编写多线程 C++ 程序。POSIX 线程(或称 Pthreads)提供了在许多类 Unix 的 POSIX 系统(如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris)上可用的 API。

创建线程

下面的例程用于创建一个 POSIX 线程:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)

这里,pthread_create 创建一个新的线程并使其可执行。这个例程可以从代码中的任何地方被多次调用。以下是参数的描述:

  1. thread

    新线程的一个不透明且唯一的标识符,由子程序返回。

  2. attr

    一个不透明的属性对象,可用于设置线程属性。你可以指定一个线程属性对象,或者用 NULL 表示默认值。

  3. start_routine

    线程创建后将执行的 C++ 例程。

  4. arg

    一个可以传递给 start_routine 的单一参数。它必须作为一个类型为 void 的指针传入。如果没有参数需要传递,则可以使用 NULL。

可以由一个进程创建的最大线程数量取决于实现。一旦创建,线程是平等的,可以创建其他线程。线程之间没有隐含的层次关系或依赖性。

终止线程

下面的例程用于终止一个 POSIX 线程:

#include <pthread.h>
pthread_exit (status)

pthread_exit 用于显式地退出一个线程。通常,在线程完成其工作并且不再需要存在时调用 pthread_exit() 例程。

如果 main() 在它创建的线程之前结束并使用 pthread_exit() 退出,则其他线程将继续执行。否则,当 main() 结束时,它们将自动终止。

示例

这个简单的示例代码使用 pthread_create() 例程创建了 5 个线程。每个线程打印一条 "Hello World!" 消息,然后通过调用 pthread_exit() 终止。

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   
   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
      
      if (rc) {
         cout << "Error: unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

编译上面的程序时,请使用 -lpthread 库:

$ gcc test.cpp -lpthread

现在,执行你的程序将会得到如下输出:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4

向线程传递参数

这个示例展示了如何通过一个结构体来传递多个参数。你可以在线程回调中传递任何数据类型,因为它指向的是 void 类型,如下例所示:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

struct thread_data {
   int  thread_id;
   char *message;
};

void *PrintHello(void *threadarg) {
   struct thread_data *my_data;
   my_data = (struct thread_data *) threadarg;

   cout << "Thread ID : " << my_data->thread_id ;
   cout << " Message : " << my_data->message << endl;

   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   struct thread_data td[NUM_THREADS];
   int rc;
   int i;

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      td[i].thread_id = i;
      td[i].message = "This is message";
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
      
      if (rc) {
         cout << "Error: unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

当上述代码被编译和执行时,它会产生如下结果:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message

加入和分离线程

下面有两个例程可以用来加入或分离线程:

pthread_join (threadid, status)
pthread_detach (threadid)

pthread_join() 子程序会阻塞调用线程直到指定的 threadid 线程终止。当一个线程被创建时,它的属性之一定义了它是可加入的还是分离的。只有那些被创建为可加入的线程才能被加入。如果一个线程是被创建为分离的,则它永远不能被加入。

下面的示例演示了如何通过 Pthread join 例程等待线程完成:

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define NUM_THREADS 5

void *wait(void *t) {
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << " ...exiting " << endl;
   pthread_exit(NULL);
}

int main () {
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;

   // Initialize and set thread joinable
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], &attr, wait, (void *)i );
      if (rc) {
         cout << "Error: unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // free attribute and wait for the other threads
   pthread_attr_destroy(&attr);
   for( i = 0; i < NUM_THREADS; i++ ) {
      rc = pthread_join(threads[i], &status);
      if (rc) {
         cout << "Error: unable to join," << rc << endl;
         exit(-1);
      }
      cout << "Main: completed thread id :" << i ;
      cout << " exiting with status :" << status << endl;
   }

   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

当上述代码被编译和执行时,它会产生如下结果:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0 exiting with status :0
Main: completed thread id :1 exiting with status :0
Main: completed thread id :2 exiting with status :0
Main: completed thread id :3 exiting with status :0
Main: completed thread id :4 exiting with status :0
Main: program exiting.
上一章 下一章
阅读号二维码

关注阅读号

联系二维码

联系我们

© 2024 Yoagoa. All rights reserved.

粤ICP备18007391号

站点地图