文章目录
  1. 1. 基本概念
  2. 2. 线程函数、实例程序说明
  1. 什么是进程?
  2. 什么是线程?
  3. 进程跟线程的关系?
  4. 引进线程的优点?

overlord tank

基本概念

preemptive multitasking抢先式多任务:意思是操作系统能够强迫应用程序把CPU分享给其他人,程序员不需要额外的努力。

程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体.

进程Process是正在执行的程序实例。进程是程序在某个数据集上的执行,是一个动态实体。所以进程因创建才会产生,调度才会运行,所以进程会因等待资源或事件而被处于等待状态,一旦完成任务而被撤消,进程反映了一个程序在一定的数据集上运行的全部动态过程

逻辑上将一个进程划分为一下几段:

  • 文本:程序的指令

  • 数据:程序使用的静态变量

  • 堆:程序可以从该区域动态分配额外内存

  • 栈:随函数调用、返回而增减的一片内存,用于为局部变量和函数调用链接信息分配存储空间

thread线程:是进程的一个实体,在一个程序中的多个执行路线就叫做线程。**每个线程都会执行相同的程序代码,共享统一数据区域和堆。可是每个线程都拥有自己的栈,用来状态本地变量和函数调用的链接信息. ** 线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

线程之间可通过共享的全局变量进行通信。借助于线程API所提供的条件变量和互斥机制,进程所属的线程之间得以相互通信并同步行为————尤其实在对共享变量的使用方面。

线程和进程的关系是:线程是属于进程的,是CPU调度和分派的基本单位。**线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。**

线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。

所有的进程至少有一个执行线程。

多线程,使程序得以将其工作分开,独立运作,不互相影响


线程函数、实例程序说明

  • pthread_create
    pthread_create 作用是创建一个新线程;
    函数原型

    1
    2
    3
    #include<pthread.h>

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

    第一个参数pthread_t *thread:线程被创建时候这个指针指向的变量中将被写入一个线程号,我们用线程号来引用新的线程。

    第二个参数pthread_attr_t *attr用于设置线程的属性;一般不需要设置特殊的属性,所以我们设置该参数为NULL

    最后2个参数分别告诉线程将要启动执行的函数void *(*start_routine)(void *) 该函数以一个指向void的指针为参数,返回的也是一个指向void的指针。因此可以传递一个任一类型的参数并返回一个任一类型的指针。
    和:传递给函数的参数void *arg

    该函数调用成功时返回值是0,如果失败则返回错误代码

  • pthread_join
    prhread_join 的作用是使一个线程等待另一个线程结束。这个函数的定义如下:

    1
    2
    #include<pthread.h>
    int pthread_join(pthread_t th,void **thread_return );

    第1个参数:指定了将要等待的线程,线程通过pthread_crtate返回的标识符来指定。

    第2个参数:是一个指针,它指向另一个指针,而后者指向线程的返回值。与pthread_create类似,这个函数在成功时返回0,失败时返回错误代码。

在Linux中,新建的线程并不是在原先的进程中,而是系统通过一个系统调用clone()。该系统copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。不过这个copy过程和fork不一样。 copy后的进程和原先的进程共享了所有的变量,运行环境。这样,原先进程中的变量变动在copy后的进程中便能体现出来。

代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。

所有线程都有一个线程号,也就是Thread ID。其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。

  • pthread_exit
    线程通过pthread_exit函数终止执行;这个函数的作用是,终止调用它的线程并返回一个指向对象的指针。

函数原型

1
2
#include<pthread.h>
void pthread_exit(void *retval);
  1. 简单的线程程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*这个程序创建了一个新线程,新线程与原先的线程共享变量,并在结束的时候向原先的线程返回一个结果*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

void *thread_function(void *arg); //需要启动的函数原型

char message[] = "Hello World";

int main() {
int res;
pthread_t a_thread; // 指向pthread_t类型数据的指针
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, (void *)message); //创建一个新的线程;新线程从 thread_function开始执行
if (res != 0) { //如果创建失败
perror("Thread creation failed");
exit(EXIT_FAILURE); //eixt 退出,退出整个程序;
}
printf("Waiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result); //这个函数等待它所指定的线程结束后才返回。参数:&thread_result是指向线程返回的指针,也就是指向 thread_function函数内的 pthread_exit;
if (res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined, it returned %s\n", (char *)thread_result);
printf("Message is now %s\n", message); // 数组message已经被新线程修改,但主线程仍能访问
exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
printf("thread_function is running. Argument was %s\n", (char *)arg);
sleep(3); //睡3秒
strcpy(message, "Bye!"); //更新全局变量
pthread_exit("*****Thank you for the CPU time"); //线程通过pthread_exit函数终止执行,这个函数退出并主动向 主线程 返回一个字符串;这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
}


/*
这个程序 一开始 用 pthread_create 创建一个线程(thread_function),如果这个线程调用成功将会有2个线程, 1个线程是main另一个线程是 thread_function函数

原先的线程在查明新线程启动后,将调用pthread_join函数;
*/
  1. 2个线程同时执行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <pthread.h>

    void *thread_function(void *arg);
    int run_now = 1;
    char message[] = "Hello World";

    int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    int print_count1 = 0;

    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) {
    perror("Thread creation failed");
    exit(EXIT_FAILURE);
    }

    while(print_count1++ < 20) { // 这个while循环 只输出1次 1
    if (run_now == 1) {
    printf("1");
    run_now = 2;
    }
    else {
    sleep(1);
    }
    }

    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
    perror("Thread join failed");
    exit(EXIT_FAILURE);
    }
    printf("Thread joined %s\n", (char *)thread_result);
    exit(EXIT_SUCCESS);
    }

    void *thread_function(void *arg) {
    int print_count2 = 0;

    while(print_count2++ < 20) {
    if (run_now == 2) {
    printf("2");
    run_now = 1;
    }
    else {
    sleep(1);
    }
    }

    sleep(3);
    pthread_exit("*******EOF*****");
    }
    每个线程通过设置run_now变量的方法通知另一个线程开始运行,然后,它会等待另一个线程改变了这个变量的值后再次运行。

    这2个线程共享run_now变量


C++11多线程

文章目录
  1. 1. 基本概念
  2. 2. 线程函数、实例程序说明