linux学习:线程

目录

线程api

创建一条新线程

获取、设置线程的分离属性

获取、设置线程是否继承创建者的调度策略

获取、设置线程的调度策略

获取、设置线程静态优先级  获取、设置线程动态优先级

获取、设置线程栈大小、警戒区大小

退出线程

接合指定线程

给指定线程发送一个取消请求

获取、设置线程的取消状态和取消类型

压栈、或弹栈线程的取消处理例程

例子

创建一条线程,他的执行例程,线程退出,并被主线程接合

产生一个包含“分离”状态的属性变量,用此变量产生线程,使该线程退出后不会变成僵尸

取消一条线程,及该线程如何正确地处理该取消请求

例子1   定义线程执行的函数、创建线程,并在主线程中等待新创建的线程执行完成

例子2  等待获取线程退出返回的int数据

例子3   等待获取线程退出返回的char*数据

例子4    创建两个线程同时对一个变量做修改

例子5   互斥锁,三个线程一个一个运行

例子6    使用互斥锁来保护共享数据

例子7    使用互斥锁来保护共享资源以避免竞争条件

例子8   一个线程等待条件变量的信号,另一个线程在满足某个条件时发送信号,以通知等待的线程

例子9    一个线程等待条件变量的信号,另一个线程在满足某个条件时发送信号,以通知等待的线程。

例子10   线程1等待条件变量的信号,一旦收到信号就执行相应的操作,而线程2在满足某个条件时发送信号给线程1


线程api

创建一条新线程

注意

  • 线程例程指的是:如果线程创建成功,那么该线程会立即去执行的函数
  • POSIX 线程库的所有 API 对返回值的处理原则都是一致的:成功返回 0,失败返 回错误码 errno
  • 线程属性如果为 NULL,则会创建一个标准属性的线程,线程的属性非常多

线程属性变量api

以上 API 都是针对线程属性操作的,所谓线程属性是类型为 pthread_attr_t 的 变量,设置一个线程的属性时,通过以上相关的函数接口,将需要的属性添加到该类型 变量里面,再通过 pthread_create( )的第二个参数来创建相应属性的线程

注意

  • 定义线程属性变量,并且使用 pthread_attr_init( )初始化。
  • 使用 pthread_attr_setXXX( )来设置相关的属性
  • 使用该线程属性变量创建相应的线程
  • 使用 pthread_attr_destroy( )销毁该线程属性变量

获取、设置线程的分离属性

一条线程如果是可接合的,意味着这条线程在退出时不会自动释放自身资源,而会成为 僵尸线程,同时意味着该线程的退出值可以被其他线程获取。因此,如果不需要某条线程的 退出值的话,那么最好将线程设置为分离状态,以保证该线程不会成为僵尸线程

获取、设置线程是否继承创建者的调度策略

当需要给一个线程设置调度方面的属性时,必须先将线程的 inheritsched 设置为 PTHREAD_EXPLICIT_SCHED

获取、设置线程的调度策略

注意

  • 当线程的调度策略为 SCHED_FIFO 时,其静态优先级(static priority)必须设 置为 1-99,这将意味着一旦这种线程处于就绪态时,他能立即抢占任何静态优先级为 0 的 普通线程。采用 SCHED_FIFO 调度策略的线程还遵循以下规则:
    • A) 当他处于就绪态时,就会被放入其所在优先级队列的队尾位置。
    • B) 当被更高优先级的线程抢占后,他会被放入其所在优先级队列的队头位置,当 所有优先级比他高的线程不再运行后,他就恢复运行。
    • C) 当他调用 sched_yield( )后,他会被放入其所在优先级队列的队尾的位置。 总的来讲,一个具有 SCHED_FIFO 调度策略的线程会一直运行直到发送 I/O 请求, 或者被更高优先级线程抢占,或者调用 sched_yield( )主动让出 CPU
  • 当线程的调度策略为 SCHED_RR 时,情况跟 SCHED_FIFO 是一样的,区别在于: 每一个 SHCED_RR 策略下的线程都将会被分配一个额度的时间片,当时间片耗光时,他 会被放入其所在优先级队列的队尾的位置。可以用 sched_rr_get_interval( )来获得时间 片的具体数值
  • 当线程的调度策略为 SCHED_OTHER 时,其静态优先级(static priority)必须 设置为 0。该调度策略是 Linux 系统调度的默认策略,处于 0 优先级别的这些线程按照所 谓的动态优先级被调度,而动态优先级起始于线程的 nice 值,且每当一个线程已处于就绪 态但被调度器调度无视时,其动态优先级会自动增加一个单位,这样能保证这些线程竞争 CPU 的公平性

获取、设置线程静态优先级  获取、设置线程动态优先级

注意

  • 静态优先级是一个定义如下的结构体
    struct sched_param
    {
        int sched_priority;
    };

    可见静态优先级就是一个只有一个整型数据的结构体,这个整型数值介于0到99之间, 0 级线程被称为非实时的普通线程,他们之间的调度凭借所谓的动态优先级来博弈。而 1-99 级线程被称为实时线程,他们之间的调度凭借他们不同级别的静态优先级和不同的调度策略 (如果他们的静态优先级一样的话)来博弈

  • 线程的静态优先级(static priority)之所以被称为“静态”,是因为只要你不强行使用相关函数修改他,他不会随着线程的执行而发生改变,静态优先级决定了实时线程的基本调度次序,如果他们的静态优先级一样,那么调度策略再为调度器提供进一步的调度依据
  • 线程的动态优先级(dynamic prioriy)是非实时的普通线程独有的概念,之所以 被称为“动态”,是因为它会随着线程的运行,根据线程的表现而发生改变,具体来讲是— —如果一条线程是“CPU 消耗型”的,比如视频解码算法,这类线程只要一运行就黏住 CPU 不放,这样的线程的动态优先级会被慢慢地降级,这符合我们的预期,因为这类线程不需要 很高的响应速度,你只要保证一定的执行时间片就可以了。相反,另一类线程被称为“IO 消耗型”,比如编辑器,这类线程绝大部分的时间都在睡眠,调度器发现每次调度他他都毅 然决然地放弃了,将宝贵的 CPU 让给了其他线程,了不起是个大好人,因此会慢慢地提高 他的动态优先级,使得这类线程在同等的非实时普通线程中,有越来越高的响应速度,表现 出更好的交互性能,这也正是我们想要的结果

获取、设置线程栈大小、警戒区大小

注意

  • 线程栈是非常重要的资源,用以存放诸如函数形参、局部变量、线程切换现场寄存器数 据等等,一个多线程进程的栈空间,包含了所有线程各自的栈

退出线程

线程跟进程类似,在缺省的状态下退出之后,会变成僵尸线程,并且保留退出值。其他线程可以通过相关 API 接合该线程——使其资源被系统回收,如果愿意的话还可以顺便获取其退出值

接合指定线程

注意

  • 如果线程退出时没有退出值,那么 retval 可以指定为 NULL
  • pthread_join( )指定的线程如果尚在运行,那么他将会阻塞等待
  • pthread_tryjoin_np( )指定的线程如果尚在运行,那么他将会立即出错返回

给指定线程发送一个取消请求

另外,或许在某个时刻不能等某个线程“自然死亡”,而需要勒令其马上结束,此时可 以给线程发送一个取消请求,让其中断执行而退出

而当线程收到一个取消请求时,他将会如何表现取决于两个东西:一是当前的取消状态, 二是当前的取消类型。线程的取消状态很简单——分别是 PTHREAD_CANCEL_ENABLE 和 PTHREAD_CANCEL_DISABLE,前者是缺省的,代表线程可以接受取消请求,后者代 表关闭取消请求,不对其响应。

而在线程接受取消请求的情况下,如何停下来又取决于两种不同的响应取消请求的策略 ——延时响应和立即响应,当采取延时策略时,线程并不会立即退出,而是要遇到所谓的“取 消点”之后,才退出。而“取消点”,指的是一系列指定的函数。

获取、设置线程的取消状态和取消类型

压栈、或弹栈线程的取消处理例程

由于线程任何时刻都有可能持有诸如互斥锁、信号量等资源,一旦被取消很有可能导致别的线程出现死锁,因此如果一条线程的确可能被取消,那么在被取消之前必须使用以下 API 来为将来可能出现的取消请求注册“处理例程”,让这些例程自动释放持有的资源

例子

创建一条线程,他的执行例程,线程退出,并被主线程接合

1 #include <stdio.h>
2 #include <pthread.h>
3 // 线程函数
4 void *routine(void *arg)
5 {
6     char *s = (char *)arg; // 将创建线程传进来的参数转换为其原本类型
7     printf("argument: %s", s);
8
9     sleep(1); // 睡眠 1 秒钟后退出
10    pthread_exit("Bye-Bye!\n");// 退出传出的值
11 }
12
13 int main(int argc, char **argv)
14 {
15     // 创建线程,指定其执行例程为 routine( )并将字符串传递给他
16     pthread_t tid;
17     pthread_create(&tid, NULL, routine, (void *)"testing string\n");
18
19     // 阻塞等待指定线程退出,并获取其退出值
20     void *p;
21     pthread_join(tid, &p);
22     // 打印其退出值
23     printf("exit value: %s", (char *)p);
24
25     return 0;
26 }

产生一个包含“分离”状态的属性变量,用此变量产生线程,使该线程退出后不会变成僵尸

1 #include <stdio.h>
2 #include <pthread.h>
3 // 线程函数
4 void *routine(void *arg)
5 {
6     pthread_exit(NULL); // 由于已分离,该线程退出后会自动释放资源
7 }
8
9 int main(int argc, char **argv)
10 {
11     // 初始化一个属性变量,并将分离属性加入该变量
12     pthread_attr_t attr;// 创建一个属性变量
13     pthread_attr_init(&attr);// 初始化线程属性变量 attr
14     pthread_attr_setdetachstate(&attr, 
15                PTHREAD_CREATE_DETACHED);// 赋值给属性变量
16
17     // 用该属性变量产生一条新线程
18     pthread_t tid;
19     pthread_create(&tid, &attr, routine, NULL);
20
21     // 主线程暂停,否则 return 语句会导致整个进程退出
22     pause();
23     return 0;
24 }

取消一条线程,及该线程如何正确地处理该取消请求

1 #include <stdio.h>
2 #include <pthread.h>
3
4 pthread_mutex_t m;// 声明了一个互斥锁 m
5 // 线程退出的时候会触发的解锁互斥锁函数
6 void handler(void *arg)
7 {
8     pthread_mutex_unlock(&m); // 解锁
9 }
10 // 线程函数
11 void *routine(void *arg)
12 {
13     // 加锁前,将 handler函数压入线程取消处理例程的栈中,以防中途被取消
14     pthread_cleanup_push(handler, NULL);
15     pthread_mutex_lock(&m);//上锁
16
17     printf("[%u][%s]: abtained the mutex.\n", 
18                 (unsigned)pthread_self(), 
19                               __FUNCTION__);
20     sleep(10); // 在此线程睡眠期间如果收到取消请求,handler 将被执行
21
22     
23     pthread_mutex_unlock(&m);// 解锁
24     pthread_cleanup_pop(0);// 将 handler函数从栈中弹出,但不执行它
25
26     pthread_exit(NULL);// 退出
27 }
28
29 int main(int argc, char **argv)
30 {
31     pthread_mutex_init(&m, NULL);// 初始化了互斥锁 m
32
33     pthread_t tid;// 新线程
34     pthread_create(&tid, NULL, routine, NULL);// 线程执行函数
35
36     // 等待 1 秒钟之后,向子线程发送一个取消请求
37     sleep(1);
38     pthread_cancel(tid);
39
40     // 此时子线程虽被取消了,但被 handler 自动释放,因此主线程可加锁
41     pthread_mutex_lock(&m);
42     printf("[%u][%s]: abtained the mutex.\n", 
43             (unsigned)pthread_self(), 
44             __FUNCTION__);
45     pthread_mutex_unlock(&m);// 解锁

46
47     return 0;
48 }

例子1   定义线程执行的函数、创建线程,并在主线程中等待新创建的线程执行完成

#include <stdio.h>
#include <pthread.h>

// pthread_create 函数原型,用于创建一个新线程
// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);

// 线程执行的函数
void *func1(void *arg)
{
    // 打印当前线程的 ID
    printf("t1:%ld thread is created\n", (unsigned long)pthread_self());
    // 打印传递给线程的参数
    printf("t1:param is %d\n", *((int *)arg));
}

int main()
{
    int ret; // 用于存储 pthread_create 函数的返回值
    int param = 100; // 传递给线程的参数
    pthread_t t1; // 线程标识符

    // 创建一个新线程,执行 func1 函数,传递 param 的地址作为参数
    ret = pthread_create(&t1, NULL, func1, (void *)&param);
    if (ret == 0) {
        // 如果线程创建成功,打印信息
        printf("main: create t1 success\n");
    }

    // 打印主线程的 ID
    printf("main:%ld\n", (unsigned long)pthread_self());

    // 等待 t1 线程结束
    pthread_join(t1, NULL);

    return 0;
}

例子2  等待获取线程退出返回的int数据

#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);

void *func1(void *arg)
{
	static int ret = 10;

	printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t1:param is %d\n",*((int *)arg));

	pthread_exit((void *)&ret);
}

int main()
{
	int ret;
	int param = 100;
	pthread_t t1;

	int *pret = NULL;

	ret = pthread_create(&t1, NULL, func1,(void *)&param);
	if(ret == 0){
		printf("main:create t1 success\n");
	}


	printf("main:%ld\n",(unsigned long)pthread_self());

	pthread_join(t1,(void **)&pret);

	printf("main: t1 quit: %d\n",*pret);

	return 0;
}

例子3   等待获取线程退出返回的char*数据

#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);

void *func1(void *arg)
{
	static char *p = "t1 is run out";

	printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t1:param is %d\n",*((int *)arg));

	pthread_exit((void *)p);
}

int main()
{
	int ret;
	int param = 100;
	pthread_t t1;

	char *pret = NULL;

	ret = pthread_create(&t1, NULL, func1,(void *)&param);
	if(ret == 0){
		printf("main:create t1 success\n");
	}


	printf("main:%ld\n",(unsigned long)pthread_self());

	pthread_join(t1,(void **)&pret);

	printf("main: t1 quit: %s\n",pret);

	return 0;
}

例子4    创建两个线程同时对一个变量做修改

#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data = 0;



void *func1(void *arg)
{
	printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t1:param is %d\n",*((int *)arg));
	while(1){

		printf("t1: %d\n",g_data++);	
		sleep(1);

		if(g_data == 3){
			pthread_exit(NULL);
		}
	}

}

void *func2(void *arg)
{
	printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t2:param is %d\n",*((int *)arg));
	while(1){

		printf("t2: %d\n",g_data++);	
		sleep(1);
	}
}

int main()
{
	int ret;
	int param = 100;
	pthread_t t1;
	pthread_t t2;

	ret = pthread_create(&t1, NULL, func1,(void *)&param);
	if(ret == 0){
		printf("main:create t1 success\n");
	}

	ret = pthread_create(&t2, NULL, func2,(void *)&param);
	if(ret == 0){
		printf("main:create t2 success\n");
	}

	printf("main:%ld\n",(unsigned long)pthread_self());
	while(1){
	
		printf("main: %d\n",g_data++);	
		sleep(1);
	}

	pthread_join(t1,NULL);
	pthread_join(t2,NULL);

	return 0;
}

例子5   互斥锁,三个线程一个一个运行

#include <stdio.h>  
#include <pthread.h>  
#include <unistd.h> // 引入sleep函数所需的头文件  
  
// 声明一个全局变量,用于多线程间共享  
int g_data = 0;  
  
// 定义一个互斥锁  
pthread_mutex_t mutex;  
  
// 线程函数1  
void *func1(void *arg)  
{  
    int i;  
  
    // 锁定互斥锁,确保同一时间只有一个线程可以执行以下代码块  
    pthread_mutex_lock(&mutex);  
  
    for(i=0;i<5;i++){  
        printf("t1:%ld 线程已创建\n",(unsigned long)pthread_self()); // 打印线程ID和消息  
        printf("t1:参数是 %d\n",*((int *)arg)); // 打印传递的参数  
        sleep(1); // 线程休眠1秒  
    }  
  
    // 解锁互斥锁,允许其他线程进入锁定的代码块  
    pthread_mutex_unlock(&mutex);  
  
    return NULL; // 线程函数返回NULL  
}  
  
// 线程函数2  
void *func2(void *arg)  
{  
    // 锁定互斥锁  
    pthread_mutex_lock(&mutex);  
  
    printf("t2:%ld 线程已创建\n",(unsigned long)pthread_self());  
    printf("t2:参数是 %d\n",*((int *)arg));  
  
    // 解锁互斥锁  
    pthread_mutex_unlock(&mutex);  
  
    return NULL;  
}  
  
// 线程函数3  
void *func3(void *arg)  
{  
    // 锁定互斥锁  
    pthread_mutex_lock(&mutex);  
  
    printf("t3:%ld 线程已创建\n",(unsigned long)pthread_self());  
    printf("t3:参数是 %d\n",*((int *)arg));  
  
    // 解锁互斥锁  
    pthread_mutex_unlock(&mutex);  
  
    return NULL;  
}  
  
int main()  
{  
    int ret;  
    int param = 100; // 定义一个整数作为线程函数的参数  
    pthread_t t1; // 声明线程t1的标识符  
    pthread_t t2; // 声明线程t2的标识符  
    pthread_t t3; // 声明线程t3的标识符  
  
    // 初始化互斥锁  
    pthread_mutex_init(&mutex, NULL);  
  
    // 创建线程t1  
    ret = pthread_create(&t1, NULL, func1,(void *)&param);  
    if(ret == 0){  
        printf("main:创建t1成功\n");  
    }  
  
    // 创建线程t2  
    ret = pthread_create(&t2, NULL, func2,(void *)&param);  
    if(ret == 0){  
        printf("main:创建t2成功\n");  
    }  
  
    // 创建线程t3(注意:这里缺少了检查ret是否为0的代码)  
    ret = pthread_create(&t3, NULL, func3,(void *)&param);  
    if(ret == 0){  
        printf("main:创建t3成功\n");  
    }  
  
    // 打印主线程的ID  
    printf("main:%ld\n",(unsigned long)pthread_self());  
  
    // 等待线程t1和t2执行完毕  
    pthread_join(t1,NULL);  
    pthread_join(t2,NULL);  
    // 注意:这里没有等待线程t3执行完毕,这可能会导致t3在main函数结束后仍在运行  
  
    // 销毁互斥锁  
    pthread_mutex_destroy(&mutex);  
  
    return 0;  
}

例子6    使用互斥锁来保护共享数据

#include <stdio.h>  
#include <pthread.h>  
#include <unistd.h> // 引入sleep函数所需的头文件  
  
// 全局变量,用于多线程间共享  
int g_data = 0;  
  
// 定义一个互斥锁  
pthread_mutex_t mutex;  
  
// 线程函数1  
void *func1(void *arg)  
{  
    // 打印线程ID和消息  
    printf("t1:%ld 线程已创建\n",(unsigned long)pthread_self());  
    // 打印传递的参数  
    printf("t1:param is %d\n",*((int *)arg));  
  
    // 锁定互斥锁  
    pthread_mutex_lock(&mutex);  
  
    // 无限循环  
    while(1){  
        // 打印并增加全局变量g_data的值(注意:这里的g_data++并不是线程安全的,但因为互斥锁,此处没有问题)  
        printf("t1: %d\n",g_data++);  
        sleep(1); // 线程休眠1秒  
  
        // 当g_data等于3时,解锁互斥锁并退出线程  
        if(g_data == 3){  
            pthread_mutex_unlock(&mutex);  
            printf("t1 退出================================\n");  
            // 注意:exit(0)会终止整个程序,而不是单个线程。应使用pthread_exit(NULL)  
            //exit(0);  
            // 因为没有使用pthread_exit(NULL),这里实际上程序会继续执行(可能导致问题)  
            break; // 使用break退出循环,但因为前面没有pthread_exit(NULL),线程并不会真正退出  
        }  
    }  
  
    // 如果前面使用了exit(0),这里就不需要了  
    // 但由于使用了break,线程将退出循环但继续执行(如果有后续代码)  
    //pthread_exit(NULL); // 正确的线程退出方式  
  
    // 注意:由于break后没有pthread_exit(NULL),且没有其他线程退出逻辑,这个线程可能会继续执行(如果有后续代码)  
    // 这可能导致程序行为不可预测,尤其是如果后续代码需要访问已经释放的资源或执行其他重要任务  
  
    // 如果func1函数后面没有其他代码,则线程将在此处自然结束(返回NULL)  
    return NULL; // 线程函数返回NULL  
}  
  
// 线程函数2  
void *func2(void *arg)  
{  
    // 打印线程ID和消息  
    printf("t2:%ld 线程已创建\n",(unsigned long)pthread_self());  
    // 打印传递的参数  
    printf("t2:param is %d\n",*((int *)arg));  
  
    // 无限循环  
    while(1){  
        // 打印全局变量g_data的值  
        printf("t2: %d\n",g_data);  
  
        // 锁定互斥锁  
        pthread_mutex_lock(&mutex);  
  
        // 增加全局变量g_data的值(线程安全)  
        g_data++;  
  
        // 解锁互斥锁  
        pthread_mutex_unlock(&mutex);  
  
        sleep(1); // 线程休眠1秒  
    }  
  
    // 注意:由于这是一个无限循环,func2线程将永远不会自然结束,除非被外部因素(如信号)终止  
    return NULL; // 实际上,这个return语句永远不会被执行  
}  
  
int main()  
{  
    int ret;  
    int param = 100; // 定义一个整数作为线程函数的参数  
    pthread_t t1; // 声明线程t1的标识符  
    pthread_t t2; // 声明线程t2的标识符  
  
    // 初始化互斥锁  
    pthread_mutex_init(&mutex,NULL);  
  
    // 创建线程t1  
    ret = pthread_create(&t1, NULL, func1,(void *)&param);  
    if(ret == 0){  
        printf("main:创建t1成功\n");  
    }  
  
    // 创建线程t2  
    ret = pthread_create(&t2, NULL, func2,(void *)&param);  
    if(ret == 0){  
        printf("main:创建t2成功\n");  
    }  
  
    // 打印主线程的ID  
    printf("main:%ld\n",(unsigned long)pthread_self());  
  
    // 无限循环,主线程持续运行并打印g_data的值  
    while(1){  
        printf("main: %d\n",g_data);  
        sleep(1);
	}

	pthread_join(t1,NULL);
	pthread_join(t2,NULL);
	pthread_mutex_destroy(&mutex);

	return 0;
}

例子7    使用互斥锁来保护共享资源以避免竞争条件

#include <stdio.h>
#include <pthread.h>

int g_data = 0; // 全局变量,共享资源

pthread_mutex_t mutex; // 互斥锁1
pthread_mutex_t mutex2; // 互斥锁2

// 线程函数1
void *func1(void *arg)
{
    int i;

    // 先获取互斥锁1
    pthread_mutex_lock(&mutex);
    sleep(1);
    // 再获取互斥锁2
    pthread_mutex_lock(&mutex2);

    // 执行循环打印信息
    for(i = 0; i < 5; i++){
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("t1:param is %d\n",*((int *)arg));
        sleep(1);
    }

    // 释放互斥锁2
    pthread_mutex_unlock(&mutex2);
}

// 线程函数2
void *func2(void *arg)
{
    // 先获取互斥锁2
    pthread_mutex_lock(&mutex2);
    sleep(1);
    // 再获取互斥锁1
    pthread_mutex_lock(&mutex);

    // 打印信息
    printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t2:param is %d\n",*((int *)arg));

    // 释放互斥锁1
    pthread_mutex_unlock(&mutex);
}

// 线程函数3
void *func3(void *arg)
{
    // 获取互斥锁1
    pthread_mutex_lock(&mutex);

    // 打印信息
    printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t3:param is %d\n",*((int *)arg));

    // 释放互斥锁1
    pthread_mutex_unlock(&mutex);
}

int main()
{
    int ret;
    int param = 100; // 线程参数
    pthread_t t1; // 线程1
    pthread_t t2; // 线程2
    pthread_t t3; // 线程3

    // 初始化互斥锁1和互斥锁2
    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&mutex2, NULL);

    // 创建线程1
    ret = pthread_create(&t1, NULL, func1, (void *)&param);
    if(ret == 0){
        printf("main:create t1 success\n");
    }

    // 创建线程2
    ret = pthread_create(&t2, NULL, func2, (void *)&param);
    if(ret == 0){
        printf("main:create t2 success\n");
    }

    // 创建线程3
    ret = pthread_create(&t3, NULL, func3, (void *)&param);
    printf("main:%ld\n",(unsigned long)pthread_self());

    // 等待线程1和线程2执行完毕
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    // 销毁互斥锁1和互斥锁2
    pthread_mutex_destroy(&mutex);
    pthread_mutex_destroy(&mutex2);

    return 0;
}

例子8   一个线程等待条件变量的信号,另一个线程在满足某个条件时发送信号,以通知等待的线程

#include <stdio.h>
#include <pthread.h>

int g_data = 0; // 全局变量,共享资源

pthread_mutex_t mutex; // 互斥锁
pthread_cond_t cond; // 条件变量

// 线程函数1
void *func1(void *arg)
{
    printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t1:param is %d\n",*((int *)arg));
    static int cnt = 0;
    
    while(1){
        // 等待条件变量发生信号
        pthread_cond_wait(&cond,&mutex);
        printf("t1 run================================\n");

        printf("t1: %d\n",g_data);    
        g_data = 0;
        sleep(1);
        if(cnt++ == 10){
            exit(1);
        }
    }

}

// 线程函数2
void *func2(void *arg)
{
    printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t2:param is %d\n",*((int *)arg));
    
    
    while(1){

        printf("t2: %d\n",g_data);
        // 获取互斥锁,对共享资源进行操作
        pthread_mutex_lock(&mutex);
        g_data++;
        // 当共享资源达到某个条件时,发送信号通知其他线程
        if(g_data == 3){
            pthread_cond_signal(&cond);
        }
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);    
        sleep(1);
    }
}

int main()
{
    int ret;
    int param = 100;
    pthread_t t1; // 线程1
    pthread_t t2; // 线程2

    // 初始化互斥锁和条件变量
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);

    // 创建线程1
    ret = pthread_create(&t1, NULL, func1,(void *)&param);
    if(ret == 0){
        // printf("main:create t1 success\n");
    }

    // 创建线程2
    ret = pthread_create(&t2, NULL, func2,(void *)&param);
    if(ret == 0){
        // printf("main:create t2 success\n");
    }

    // 等待线程1和线程2执行完毕后退出
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

例子9    一个线程等待条件变量的信号,另一个线程在满足某个条件时发送信号,以通知等待的线程。

不同之处在于,这里使用了互斥锁和条件变量的静态初始化方式,而不是动态初始化

#include <stdio.h>
#include <pthread.h>

int g_data = 0; // 全局变量,共享资源

// 互斥锁和条件变量的静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 条件变量

// 线程函数1
void *func1(void *arg)
{
    printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t1:param is %d\n",*((int *)arg));
    static int cnt = 0;
    
    while(1){
        // 等待条件变量的信号
        pthread_cond_wait(&cond,&mutex);
        printf("t1 run================================\n");

        printf("t1: %d\n",g_data);    
        g_data = 0;
        sleep(1);
        if(cnt++ == 10){
            exit(1); // 达到退出条件,退出线程
        }
    }

}

// 线程函数2
void *func2(void *arg)
{
    printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t2:param is %d\n",*((int *)arg));
    
    while(1){
        printf("t2: %d\n",g_data);
        // 获取互斥锁,对共享资源进行操作
        pthread_mutex_lock(&mutex);
        g_data++;
        // 当共享资源达到某个条件时,发送条件变量的信号通知等待的线程
        if(g_data == 3){
            pthread_cond_signal(&cond);
        }
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);    
        sleep(1);
    }
}

int main()
{
    int ret;
    int param = 100; // 线程参数
    pthread_t t1; // 线程1
    pthread_t t2; // 线程2

    // 创建线程1
    ret = pthread_create(&t1, NULL, func1,(void *)&param);
    if(ret == 0){
        // printf("main:create t1 success\n");
    }

    // 创建线程2
    ret = pthread_create(&t2, NULL, func2,(void *)&param);
    if(ret == 0){
        // printf("main:create t2 success\n");
    }

    // 等待线程1和线程2执行完毕后退出
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

例子10   线程1等待条件变量的信号,一旦收到信号就执行相应的操作,而线程2在满足某个条件时发送信号给线程1

#include <stdio.h>
#include <pthread.h>

int g_data = 0; // 全局变量,共享资源

pthread_mutex_t mutex; // 互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 条件变量,静态初始化

// 线程函数1
void *func1(void *arg)
{
    printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t1:param is %d\n",*((int *)arg));
    
    while(1){
        printf("t1: %d\n",g_data);    
        sleep(1);
        pthread_cond_wait(&cond,&mutex); // 等待条件变量的信号
        if(g_data == 3){
            printf("t1 quit================================\n");
            // pthread_exit(NULL); // 可以添加线程退出操作
        }
    }
}

// 线程函数2
void *func2(void *arg)
{
    printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t2:param is %d\n",*((int *)arg));
    
    while(1){
        printf("t2: %d\n",g_data);
        pthread_mutex_lock(&mutex);
        g_data++;
        pthread_mutex_unlock(&mutex);
        if(g_data == 3){
            pthread_cond_signal(&cond); // 发送条件变量的信号通知等待的线程
        }
        sleep(1);
    }
}

int main()
{
    int ret;
    int param = 100; // 线程参数
    pthread_t t1; // 线程1
    pthread_t t2; // 线程2

    // 初始化互斥锁
    pthread_mutex_init(&mutex,NULL);

    // 创建线程1
    ret = pthread_create(&t1, NULL, func1,(void *)&param);
    if(ret == 0){
        // printf("main:create t1 success\n");
    }

    // 创建线程2
    ret = pthread_create(&t2, NULL, func2,(void *)&param);
    if(ret == 0){
        // printf("main:create t2 success\n");
    }

    // 等待线程1和线程2执行完毕后退出
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    
    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}

 

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值