资源描述
///////////////////////// 第三天 线程 基本使用方法 /////////////////////////////////////////////////////////////
二、线程
1.基本概念
线程 :是一个独立的指令流,是在某个进程中被创建的。它生存在进程资源
拥有独立的控制流,随进程的关闭而关闭
指令流:即代码段,独立是指独立于进程
进程:进程是执行程序的过程,拥有完整的资源。即进程有自已的数据段、堆栈段、代码段
即进程是运行的程序
进程
系统中程序执行和资源分配的基本单位
每个进程有自己的数据段、代码段和堆栈段
在进行切换时需要有比较复杂的上下文切换
线程
减少处理机的空转时间,支持多处理器以及减少上下文切换开销, 比创建进程小很多
进程内独立的一条运行路线
处理器调度的最小单元,也称为轻量级进程
可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享
线程
线程相关的执行状态和存储变量放在线程控制表内
一个进程可以有多个线程,有多个线程控制表及堆栈寄存器,共享一个用户地址空间
2.线程函数
#include <pthread.h>
1)创建线程
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg);
restrict thread :线程的ID号 指针类型,创建完的线程ID写入在这个参数
restrict attr :线程的属性是结构体 pthread_attr_t的指针 用来设置
start_routine :是线程函数的指针,也是线程函数的入口点,创建后马上执行线程函数。
即把输入的实参(函数)当作了独立的指令流
restrict arg :参数列表
用于等待线程的结束,是一个阻塞函数
int pthread_join(pthread_t thread, void **value_ptr);
thread : 线程的ID
value_ptr:线程的返回值
编译时,必须引入-lpthread 库
gcc -o test test.c -lpthread
void* run(void* a){
char *p=(char *)a;
int i=0;
while(i<10){
printf("thread--------run %d\n",i++);
sleep(1);
}
}
int main(int argc,char **argv){
pthread_t tid;
char buf[256]="aaa";
pthread_create(&tid,NULL, run,(void*)buf);
pthread_join(tid,NULL);
}
2)跳出线程的方式
关键点在于结束线程的函数
(1)从线程内用return 跳出线程,线程结束,函数的结束就是线程的结束
(2)在线程内调用pthread_exit函数
void pthread_exit(void *value_ptr)
value_ptr是线程的返回值
(3)从线程外面调用pthread_cancel函数
int pthread_cancel(pthread_t thread);
thread是线程ID
例:
11 void *thr_fn1(void *arg){
12 return (void*)23;//用return跳出线程
13 }
14 void *thr_fn2(void *arg){
15 pthread_exit((void*)24);
16 }
17 void *thr_fn3(void *arg){
18 while(1) sleep(1);
19 }
20
21
22 int main(int argc,char **argv){
23 void *tret;
24 pthread_t tid1,tid2,tid3;
25 pthread_create(&tid1,NULL,thr_fn1,NULL);
26 pthread_join(tid1,&tret);
27 printf("---1 %d\n",tret);
28 pthread_create(&tid2,NULL,thr_fn2,NULL);
29 pthread_join(tid2,&tret);
30 printf("---2 %d\n",tret);
31 pthread_create(&tid3,NULL,thr_fn3,NULL);
32 pthread_cancel(tid3);
33 pthread_join(tid3,&tret);
34 printf("---3 %d\n",tret);
35
36 return 0;
37 }
3)线程属性设置
pthread_attr_t attr; //定义结构的变量
pthread_init(&attr); //对属性结构进行初始化,通过函数对结构进行初始化
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//添加属性
pthread_create(&tid1,&attr,thr_fn1,NULL);
pthread_atrr_destroy(&attr); //销毁属性
...
pthread_join(tid1);
《练习》用QT编写wav音频播放器
思考的问题:
1.如何能自动读取出采样大小、频率、声道,而不需要输入
2.如何在播放时可以让界面正常,且可以点击其它按钮并停止
3.播放器应该包括哪些操作
《练习》用qt及线程编写wav播放器
//**********************************
//mplay.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/soundcard.h>
#include <unistd.h>
#include <QDebug>
#define READSIZE 80
struct FILE_FRM{
pthread_t tid; //线程id
long fd; //文件描述符
long start; //声频的起始位置
short channels; //声道 0单声道,1双声道
short format; //采样格式 8位, 16位
short speed; //频率 8k 11.025k 12k 22.05k 37.8k 44.1k
long size; //音频数据的大小
long pos; //播放位置
} file_frm={0,0,0,0,0,0,0,0};
static int isstop=0;
static int ispause=0;
static FUN_STATE audio_setstate=NULL;
/*
state 1 开始运行,
0 结束
2 代表传送的是 pos
3 代表总长度值
4 暂停
*/
//--------------------------------------------------------------------
void audio_set(FUN_STATE *fun){
audio_setstate=fun;
}
void audio_setvol(int lvol,int rvol){
int fd=open("/dev/mixer",O_RDWR);
short vol=(lvol<<8 | rvol); //音量,用16位整数记录左右声道音量
ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol);//设音量
close(fd);
}
void audio_getvol(int *lvol,int *rvol){
int fd=open("/dev/mixer",O_RDWR);
short vol;
ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&vol);//读音量
*lvol= vol >>8;
*rvol= vol & 0xFF;
close(fd);
}
static int fileopen(char *filename){
char buf[256]={0};
file_frm.fd=open(filename,O_RDONLY);
if (file_frm.fd==-1){
printf("---------- open file err\n");
return -1;
}
file_frm.start=0x28+4; //即头长44
//读文件格式
lseek(file_frm.fd,0x08,0);
read(file_frm.fd,buf,4);
if (strcmp(buf,"WAVE")!=0){
qDebug("file is not WAV\n");
close(file_frm.fd);
file_frm.fd=0;
return -1;
}
//读声道
lseek(file_frm.fd,0x16,0);
read(file_frm.fd,&file_frm.channels,2);//使用时需要-1
//读频率
lseek(file_frm.fd,0x18,0);
read(file_frm.fd,&file_frm.speed,2);
//采样格式
lseek(file_frm.fd,0x22,0);
read(file_frm.fd,&file_frm.format,2);
//音频数据长度 不包括头长
lseek(file_frm.fd,0x28,0);
read(file_frm.fd,&file_frm.size,4);
return 0;
}
void *_play(void *val){
isstop=0;
ispause=0;
struct FILE_FRM *filefrm=(struct FILE_FRM *)val;
//读取音频文件头信息****************************
//------------------------
qDebug("fd=%d,channels=%d,bits=%d,speed=%d",filefrm->fd,filefrm->channels,filefrm->format,filefrm->speed);
char buf[256]={0};
//打开设备
int dsp_fd=open("/dev/dsp",O_RDWR);
if (dsp_fd==-1) {
qDebug("dsp open err\n");
return (void*)-2;
}
ioctl(dsp_fd,SNDCTL_DSP_STEREO,&filefrm->channels);
ioctl(dsp_fd,SNDCTL_DSP_SETFMT,&filefrm->format);
ioctl(dsp_fd,SNDCTL_DSP_SPEED,&filefrm->speed);
/*
state 1 开始运行,
0 结束
2 代表传送的是 pos
3 代表总长度值
4 暂停
*/
audio_setstate(1,0); //开始运行
//S=R(采样频率Hz )×D(录音时间)×r(量化位数(位)) ×声道数/8
//S: 字节; R:HZ; D:录音时间S; r:量化位数bit
//D=Size/(R*r*c/8);
//t=size/(44100*8*2/8);
//或 WAV文件的字节数/每秒=采样频率(Hz)×量化位数(位) ×声道数/8
//s=44100*8*2/8; //s是速度
//t=size/s;
audio_setstate(3,filefrm.size/(filefrm.speed * filefrm.format *filefrm.channels/8)); //音频数据长度
for(filefrm.pos=0;filefrm.pos < filefrm.size;){
audio_setstate(2,filefrm.pos/(filefrm.speed * filefrm.format *filefrm.channels/8)); //播放位置
if(isstop) break;
while (ispause) {
audio_setstate(4,0);//暂停
usleep(50000);
}
int len=read(filefrm.fd,buf,READSIZE);
write(dsp_fd,buf,len);
filefrm.pos+=len;
}
audio_setstate(0,0); //结束
printf("play over\n");
close(dsp_fd);
close(filefrm.fd);
filefrm.fd=0;
return 0;
}
void audio_play(char *buf){
if (fileopen(char *filename)!=0) return;
pthread_create(&tid,NULL,&_play,(void*)buf);
}
void audio_stop(){
if (filefrm.fd <=0) return;
isstop=1;
if (tid!=0){
pthread_join(tid,NULL);
tid=0;
}
if (filefrm.fd>0){
close(filefrm.fd);
filefrm.fd=0;
}
}
void audio_pause(){
if (filefrm.fd <=0) return;
ispause=1;
}
void audio_replay(){
if (filefrm.fd <=0) return;
ispause=0;
audio_setstate(1,0); //开始运行
}
void audio_playfrom(int pos){//从指定位置播放
if (filefrm.fd <=0) return;
ispause=1;
filefrm.pos=pos>filefrm.size?filefrm.size:pos;
qDebug("---- new pos %d",wavpos);
lseek(filefrm.fd,filefrm.pos+filefrm.start,0);
ispause=0;
}
void audio_fastpre(int diff){//快进
if (filefrm.fd <=0) return;
audio_playfrom(filefrm.pos-diff);
}
void audio_fastnex(int diff){//快退
if (filefrm.fd <=0) return;
audio_playfrom(filefrm.pos+diff);
}
//**********************************
//mplay.h
#ifndef PLAY_H
#define PLAY_H
typedef void (*FUN_STATE)(int state,int val);
extern void audio_play(char *buf);
extern void audio_replay();
extern void audio_pause();
extern void audio_stop();
extern void audio_playfrom(int pos);
extern void audio_fastpre(int diff);
extern void audio_fastnex(int diff);
extern void audio_getvol(int *lvol,int *rvol);
extern void audio_setvol(int lvol,int rvol);
extern void audio_set(FUN_STATE *fun);
#endif // PLAY_H
//************************************
//frmmain.cpp
Filerw *pw;
void statefun(int state,int val){
if (state==3) //音频数据大小
timeLd->setMaximum(val);
else if(state==2) //播放位置状态显示
timeLd->setValue(val);
else if (state==4){//暂停状态
pauseBtn->setEnabled(false);
playBtn->setEnabled(true);
}
else if (state==1){ //播放状态
ui->pauseBtn->setEnabled(true);
ui->playBtn->setEnabled(false);
ui->nextBtn->setEnabled(true);
ui->preBtn->setEnabled(true);
ui->stopBtn->setEnabled(true);
}
else if(state==0){ //停止状态
pauseBtn->setEnabled(false);
playBtn->setEnabled(true);
nextBtn->setEnabled(false);
preBtn->setEnabled(false);
stopBtn->setEnabled(false);
timeLd->setValue(0);
}
}
Filerw::init(){
}
Filerw::Filerw(QWidget *parent) : QWidget(parent)
{
init();//创建组件
code=QTextCodec::codecForLocale();
pw= this;
audio_set(statefun);
int lvol,rvol;
audio_getvol(&lvol,&rvol);
volSLd->setValue((lvol+rvol)/2);
//
statefun(0,0);
}
Filerw::~Filerw()
{
}
void Filerw::on_playBtn_clicked()
{ //播放
if (isplaying==0){
if (fileName=="") return;
char *file=code->fromUnicode(fileName).data();
audio_play(file);
}
else if (ispause==1){
audio_replay();
}
}
void Filerw::on_pauseBtn_clicked()
{
audio_pause();
}
void Filerw::on_openBtn_clicked()
{
fileName = QFileDialog::getOpenFileName(this,
code->toUnicode("打开音频文件"), "/home/", code->toUnicode("音频文件 (*.wav *.mp3 *.wma)"));
ui->fileLb->setText(fileName);
}
void Filerw::on_volSl_valueChanged(int value)
{
audio_setvol(value);
}
void Filerw::on_timeLd_sliderMoved(int position)
{
audio_pause();
sliderpos=position;
}
void Filerw::on_timeLd_sliderReleased()
{
if (sliderpos!=0 && isplaying==1){
audio_playfrom(sliderpos);
qDebug("position=%d",sliderpos);
sliderpos=0;
}
if (ispause==1) audio_replay();
}
void Filerw::on_preBtn_clicked()
{
audio_fastpre(ui->timeLd->maximum()/20);
}
void Filerw::on_nextBtn_clicked()
{
audio_fastnex(ui->timeLd->maximum()/20);
}
void Filerw::on_stopBtn_clicked()
{
audio_stop();
}
void Filerw::on_exitBtn_clicked()
{
close();
}
展开阅读全文