Linux 多线程

Linux 多线程

一、线程简介

线程是一个进程内的基本调度单位,好比轻量级的进程。
1.多个线程在一个进程的共享内存空间中并发执行,它们共享一个进程的资源,如文件描述符和信号处理等,大大减少了上下文的开销。 运行于一个进程中的多个线程。

2.它们彼此之间使用相同的地址空间
共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间。

3.线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
总的说来, 一个进程的开销大约是一个线程开销的 30 倍左右。 不同进程具有独立的数据空间,其数据的传递只能通过通信的方式进行,费时且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,不仅快捷,而且方便。
使用多线程能带来更方便的通信机制。 多线程程序作为一种多任务、并发的工作方式,有以下几大优点:
(1) 提高应用程序响应;
(2)使多 CPU 系统更加有效;
(3)改善程序结构。

二、Linux上线程开发API概要

多线程开发在 Linux 平台上已经有成熟的 pthread 库支持。其涉及的多线程开发的最基本概念主要包含三点:线程,互斥锁,条件。其中,线程操作又分线程的创建,退出,等待 3 种。互斥锁则包括 4 种操作,分别是创建,销毁,加锁和解锁。条件操作有 5 种操作:创建,销毁,触发,广播和等待。其他的一些线程扩展概念,如信号灯等,都可以通过上面的三个基本元素的基本操作封装出来。详细请见下表:在这里插入图片描述

三、 与线程自身相关API

1. 线程创建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号

第一个参数为指向线程标识符的指针;
第二个参数用来设置线程属性,设为NULL时将生成默认属性的线程;
第三个参数是线程运行函数的起始地址;
最后一个参数是运行函数的参数,不需要参数时最后一个参数设为空指针 NULL。
当创建线程成功时,函数返回 0,若不为 0 则说明创建线程失败。 创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
 2. 线程退出

#include <pthread.h>
int pthread_exit(void *rval_ptr);

rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。
3. 线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号
  • 一个线程的结束有两种途径,一种是函数结束了,调用它的线程也就结束 了;另一种方式是通过函数 pthread_exit 来实现。
  • 唯一的参数是函数的返回代码,也就是 pthread_exit()调用者线程的返回值, 可由 pthread_join 来检索获取。只要
    pthread_join 中的第二个参数rval_ptr不是 NULL,这个值将被传递给 rval_ptr。
#include<pthread.h>
#include<stdio.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *start(void *arg)
{
        static int date=10;
        printf("This is my pid%ld\n",(unsigned long)pthread_self());
        printf("arg is %d\n",*((int *)arg));//打印传过来的参数
        pthread_exit((void *)&date);//结束线程,返回参数date给pthread_join接收
}
int main()
{
        int ret;
        pthread_t t1;
        int arg=100;

        int *msg;
        ret=pthread_create(&t1,NULL,start,(void *)&arg);//创建一个t1线程
                           //从start函数开始运行,arg是传给的参数
        if(ret==0){
                printf("the pthread create yes\n");

        }else{
                printf("pthread failed\n");
        }
        pthread_join(t1,(void **)&msg);//等待pthread_exit传过来的参数,接收到msg中
        printf("msg =%d\n",*msg);//打印线程结束返回的参数
        return 0;
}


4. 线程脱离

pthread_detach函数把指定的线程转变为脱离状态。

#include <pthread.h>
int pthread_detach(pthread_t thread);

若成功返回0,否则返回错误编号,本函数通常由想让自己脱离的线程使用,就如以下语句:

pthread_detach(pthread_self());

5.线程ID获取及比较

#include <pthread.h>
pthread_t pthread_self(void);

返回:调用线程的ID

四、互斥锁机制API

1.创建及销毁互斥锁

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

返回:若成功返回0,否则返回错误编号
要用默认的属性初始化互斥量,只需把attr设置为NULL。
2. 加锁及解锁

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

返回:若成功返回0,否则返回错误编号

五、条件变量API

1.创建及销毁条件变量

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);

除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。
2. 等待

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//一直等待
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
//一段时间后返回

3. 触发

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t cond);//两个线程发送触发条件
int pthread_cond_broadcast(pthread_cond_t cond);//多个线程广播条件触发

五、代码

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

static int a = 0;
pthread_mutex_t mutex;//创造一个锁
pthread_cond_t cond;//创造条件变量

void *fun1(void *arg)
{
	printf("t1: %ld is create\n",(unsigned long)pthread_self());
	printf("t1:value is %d\n",*((int *)arg));
	int cnt = 1;
	while(1){
			pthread_cond_wait(&cond, &mutex);//等待条件
			printf("t1 run=====================\n");
			printf("t1 :%d\n",a++);
			a = 0;
			if(cnt++ == 5){
				exit(0);
			}
			sleep(1);
	}
//	pthread_exit((void *)p);
}

void *fun2(void *arg)
{
	printf("t2: %ld is create\n",(unsigned long)pthread_self());
	printf("t2:value is %d\n",*((int *)arg));
	while(1){
		pthread_mutex_lock(&mutex);//上锁
		printf("t2 :%d\n",a++);
		if(a == 3)
			pthread_cond_signal(&cond);//发送条件
		pthread_mutex_unlock(&mutex);//解锁
		sleep(1);
	}
}
int main()
{
	pthread_t t1,t2;	
	int ret1,ret2;
	int pro = 100;
	char *p;
	pthread_mutex_init(&mutex,NULL);//锁初始化,动态初始化,宏就是静态初始化
	pthread_cond_init(&cond, NULL);//条件初始化,动态初始化,宏就是静态初始化
	
	ret1 = pthread_create(&t1,NULL,fun1,(void *)&pro);//创建线程
	ret2 = pthread_create(&t2,NULL,fun2,(void *)&pro);//创建线程
	
	pthread_join(t1,NULL);
	pthread_join(t2,NULL);
//	printf("main: ti quit : %s\n",p);
	pthread_mutex_destroy(&mutex);//销毁锁
	pthread_cond_destroy(&cond);//销毁条件
	return 0;
}

六、测试代码

vi text.c

做一个for循环,运行

./a.out 10 >>text1.txt

将运行结果10次导入到txt文本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值