线程

线程

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

有关线程的函数

1
2
3
4
5
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg);
int pthread_join (pthread_t tid, void ** status);
pthread_t pthread_self (void);
int pthread_detach (pthread_t tid);
void pthread_exit (void *status);

pthread_create用于创建一个线程,成功返回0,否则返回Exxx(为正数)。

  • pthread_t tid:线程id的类型为pthread_t,通常为无符号整型,当调用pthread_create成功时,通过tid指针返回。
  • const pthread_attr_t *attr:指定创建线程的属性,如线程优先级、初始栈大小、是否为守护进程等。可以使用NULL来使用默认值,通常情况下我们都是使用默认值。
  • void *(*func) (void *):函数指针func,指定当新的线程创建之后,将执行的函数。
  • void *arg:线程将执行的函数的参数。如果想传递多个参数,请将它们封装在一个结构体中。
  • pthread_join用于等待某个线程退出,成功返回0,否则返回Exxx(为正数)。

pthread_t tid:指定要等待的线程ID

  • void ** status:如果不为NULL,那么线程的返回值存储在status指向的空间中(这就是为什么status是二级指针的原因!这种才参数也称为“值-结果”参数)。
  • pthread_self用于返回当前线程的ID。

pthread_detach用于是指定线程变为分离状态,就像进程脱离终端而变为后台进程类似。成功返回0,否则返回Exxx(为正数)。变为分离状态的线程,如果线程退出,它的所有资源将全部释放。而如果不是分离状态,线程必须保留它的线程ID,退出状态直到其它线程对它调用了pthread_join。

进程也是类似,这也是当我们打开进程管理器的时候,发现有很多僵死进程的原因!也是为什么一定要有僵死这个进程状态。

pthread_exit用于终止线程,可以指定返回值,以便其他线程通过pthread_join函数获取该线程的返回值。

void *status:指针线程终止的返回值。

Pthread互斥

互斥使用pthread_mutes_t对象表示,下面是定义和初始化一个互斥体mutex:

1
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

对互斥加锁

1
2
#include <pthread.h>
int pthread_mutex_lock (pthread_mutex_t *mutex);

成功调用会阻塞调用的线程,直到由mutex指向的互斥体变得可用。一旦互斥体变得可用,调用线程就会被唤醒,函数返回0

对互斥解锁

1
2
#include <pthread.h>
int pthread_mutex_unlock (pthread_mutex_t *mutex);

成功调用会释放由mutex所指向的互斥体并返回0

线程间的同步

使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止。相关函数如下:

1
2
3
4
#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);
int pthread_cond_signal(pthread_cond_t *cptr);

pthread_cond_wait用于等待某个特定的条件为真,pthread_cond_signal用于通知阻塞的线程某个特定的条件为真了。在调用者两个函数之前需要声明一个pthread_cond_t类型的变量,用于这两个函数的参数。

为什么条件变量始终与互斥锁一起使用,对条件的测试是在互斥锁(互斥)的保护下进行的呢?因为“某个特性条件”通常是在多个线程之间共享的某个变量。互斥锁允许这个变量可以在不同的线程中设置和检测。

通常,pthread_cond_wait只是唤醒等待某个条件变量的一个线程。如果需要唤醒所有等待某个条件变量的线程,需要调用:

1
int pthread_cond_broadcast (pthread_cond_t * cptr);

默认情况下面,阻塞的线程会一直等待,知道某个条件变量为真。如果想设置最大的阻塞时间可以调用:

1
int pthread_cond_timedwait (pthread_cond_t * cptr, pthread_mutex_t *mptr, const struct timespec *abstime);

如果时间到了,条件变量还没有为真,仍然返回,返回值为ETIME。

例程

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
58
59
60
61
62
63
64
65
66
67
68
69
/*
是否熟悉POSIX多线程编程技术?如熟悉,编写程序完成如下功能:
1)有一int型全局变量g_Flag初始值为0;
2)在主线称中起动线程1,打印“this is thread1”,并将g_Flag设置为1
3)在主线称中启动线程2,打印“this is thread2”,并将g_Flag设置为2
4)线程序1需要在线程2退出后才能退出
5)主线程在检测到g_Flag从1变为2,或者从2变为1的时候退出
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>

typedef void *(*fun)(void *);

int g_Flag = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *thread1(void *);
void *thread2(void *);

int main(int argc, char **argv)
{
printf("enter main\n");
pthread_t tid1, tid2;
int rc1 = 0, rc2 = 0;
rc2 = pthread_create(&tid2, NULL, thread2, NULL);
if (rc2 != 0)
printf("%s: %d\n", __func__, strerror(rc2));

rc1 = pthread_create(&tid1, NULL, thread1, &tid2);
if (rc1 != 0)
printf("%s: %d\n", __func__, strerror(rc1));

pthread_cond_wait(&cond, &mutex);
printf("leave main\n");
exit(0);
}

void *thread1(void *arg)
{
printf("enter thread1\n");
printf("this is thread1, g_Flag: %d, thread id is %u\n", g_Flag, (unsigned int)pthread_self());
pthread_mutex_lock(&mutex);
if (g_Flag == 2)
pthread_cond_signal(&cond);
g_Flag = 1;
printf("this is thread1, g_Flag: %d, thread id is %u\n", g_Flag, (unsigned int)pthread_self());
pthread_mutex_unlock(&mutex);
pthread_join(*(pthread_t *)arg, NULL);
printf("leave thread1\n");
pthread_exit(0);
}

void *thread2(void *arg)
{
printf("enter thread2\n");
printf("this is thread2, g_Flag: %d, thread id is %u\n", g_Flag, (unsigned int)pthread_self());
pthread_mutex_lock(&mutex);
if (g_Flag == 1)
pthread_cond_signal(&cond);
g_Flag = 2;
printf("this is thread2, g_Flag: %d, thread id is %u\n", g_Flag, (unsigned int)pthread_self());
pthread_mutex_unlock(&mutex);
printf("leave thread2\n");
pthread_exit(0);
}

线程
https://carl-5535.github.io/2022/11/18/Linux系统编程/线程/
作者
Carl Chen
发布于
2022年11月18日
许可协议