Linux线程编程记录

1.线程

        一个进程包含一个或多个执行线程(通常只叫线程),线程是进程中的活动单位。线程是一种抽象,它负责执行代码和维护进程的运行状态。
        大部分进程只包含一个线程,它们被称为单线程(singel-thread),包含多个线程的进程称为多线程的(multithreaded)。从传统上将,因为Unix保持简洁、期望加快进程创建时间、保持健壮的进程通信机制,这些都减少了对线程的需求。可以说,Unix程序被单线程化了。
        线程包含栈(如同在非线程系统上的进程栈,主要用于存储局部变量)、处理器状态、目标代码的当前位置(通常是处理器的指针指令)。进程剩下的部分由所有线程共享。
        Linux内核实现了一个独特的线程视图;他们是偶然共享某些资源的(大多情况下是一个地址空间)进程。在用户空间,Linux根据POSIX1003.1c实现线程(pthread)。目前Linux线程实现的名称为Native POSIX Threading Li-brary(NPTL)是glib库的一部分。

2.进程与线程的区别

进程与线程

        UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务。

        进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位。在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。

        线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。线程包含了表示进程内执行环境必须的信息,其中包括进程中表示线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno常量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。在Unix和类Unix操作系统中线程也被称为轻量级进程(lightweight processes),但轻量级进程更多指的是内核线程(kernel thread),而把用户线程(user thread)称为线程。

“进程——资源分配的最小单位,线程——程序执行的最小单位”

        进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

为什么要用线程

        总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。

        使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

        使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方

        除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:

  • 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
  • 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
  • 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

3.线程的创建及等待

语法

int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);            //创建线程,若成功返回0,否则返回错误编号

/*相关参数含义:*/

pthread_t *restrict tid: pthread_t //是一个自定义的无符号的长整型

const pthread_attr_t *restrict attr	//线程的属性

void *(*start_rtn)(void *)	//干活的线程,调用相关的函数

void *restrict arg	//要传递的参数

/*当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。
新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
*/

相关API

int pthread_exit(void *rval_ptr);	//线程的退出

int pthread_join(pthread_t thread, void **rval_ptr);	// 线程的等待,成功返回0,否则返回错误编号

pthread_t pthread_self(void);	// 返回:调用线程的ID

4.创建一个线程

void* funct1(void* arg){
    
    
 
        printf("this a thread:%ld\n",(unsigned long)pthread_self());//%ld,长整型,打印调用线程的ID
        printf("param=%d\n",*((int*)arg));//打印传入参数的值
}
int main(){
    
    
        int param=500;
        pthread_t t1;
 
        int ret=pthread_create(&t1,NULL,funct1,(void*)&param);//创建一个线程
        if(ret == 0){
    
    
                printf("creat thread success!\n");
        }
        else{
    
    
                printf("creat thread errno!\n");
        }
 
        printf("man;%ld\n",(unsigned long)pthread_self());//打印主线程ID
        for(;;);
        return 0;
}

5.线程等待

void* funct1(void* arg){
    
    
 
        static int ret=10;//这里必须加static,不然会出错
        printf("this a thread:%ld\n",(unsigned long)pthread_self());//%ld,长整型,打印调用线程的ID
        printf("param=%d\n",*((int*)arg));//打印传入参数的值
        pthread_exit((void*)&ret);//线程的退出
int main(){
    
    
        int param=500;
        pthread_t t1;
        int* pret=NULL;
        
        int ret=pthread_create(&t1,NULL,funct1,(void*)&param);//创建一个线程
        if(ret == 0){
    
    //判断线程是否创建成功
                printf("creat thread success!\n");
        }       
        else{
    
    
                printf("creat thread errno!\n");
        }       
        printf("man;%ld\n",(unsigned long)pthread_self());//打印主线程的ID号
        
        int join=pthread_join(t1,(void**)&pret);//等待线程的退出,如果不退出就阻塞在这里,且后面的程序不会执行
        
        if(join == 0){
    
    //判断是否退出成功
                printf("exit the thread success!\n");
                printf("man:ti quit:%d\n",*pret);
        }       
        else{
    
    
                printf("exit the thread errno!\n");
        }       
        return 0;
} 

6.线程共享内存代码验证

int data=0;
void* funct1(void* arg){
    
    
        static char* ret="thread t1:you are a lucky dog";
        printf("pthread t1:%ld\n",(unsigned long)pthread_self());//打印当前线程号
        printf("prama=%d\n",*((int*)arg));
        while(1){
    
    
                printf("data1=%d\n",data++);
                sleep(1);
        }
        pthread_exit((void*)ret);//进程退出
}
 
void* funct2(void* arg){
    
    
        static char* ret="thread t2:you are a single dog";
        printf("pthread t1:%ld\n",(unsigned long)pthread_self());//打印当前线程号
        printf("prama=%d\n",*((int*)arg));
        while(1){
    
    
                printf("data2=%d\n",data++);
                sleep(1);
        }
        pthread_exit((void*)ret);//进程退出
}
 
int main(){
    
    
 
        pthread_t t1;//线程t1
        pthread_t t2;//线程t2
        int prama=590;//要传入的参数
        int prama2=999;
        char* pret=NULL;
        char* pret2=NULL;
 
        int ret=pthread_create(&t1,NULL,funct1,(void*)&prama);//创建线程
        if(ret == 0){
    
    
                printf("create pthread success!\n");
        }
        else{
    
    
                printf("creat pthread errno!\n");
        }
        int ret2=pthread_create(&t2,NULL,funct2,(void*)&prama2);//创建线程
        if(ret2 == 0){
    
    
                printf("create pthread2 success!\n");
        }
        else{
    
    
                printf("creat pthread2 errno!\n");
        }
        while(1){
    
    
                printf("data3=%d\n",data++);
                sleep(1);
        }
        int thread=pthread_join(t1,(void**)&pret);//等待进程退出
        if(thread == 0){
    
    
                printf("exit t1 thread success!\n");
        }
        else{
    
    
                printf("exit t1 thread errno!\n");
        }
        int thread2=pthread_join(t2,(void**)&pret2);//等待进程退出
        if(thread2 == 0){
    
    
                printf("exit t2 thread success!\n");
        }
        else{
    
    
                printf("exit t2 thread errno!\n");
        }
 
        printf("main pthread:%ld\n",(unsigned long)pthread_self());
        printf("ptread t1:%s\n",pret);
        printf("ptread t2:%s\n",pret2);
        for(;;);//主线程不退出
        return 0;
}

7.线程同步之互斥量上锁与解锁

相关API

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);	//初始化锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);	//销毁锁
// 返回:若成功返回0,否则返回错误编号

int pthread_mutex_lock(pthread_mutex_t *mutex);	//加锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);	//解锁
// 返回:若成功返回0,否则返回错误编号

上锁与解锁

pthread_mutex_t mutex;//创建锁
void* funct1(void* arg){
    
    
 
        pthread_mutex_lock(&mutex);//上锁
        int i;
        for(i=0;i<5;i++){
    
    
        printf("t1 pthread:%ld\n",(unsigned long)pthread_self());
        printf("t1 arg=%d\n",*((int*)arg));
        sleep(2);
        }
        pthread_mutex_unlock(&mutex);//解锁     
}
 
void* funct2(void* arg){
    
    
 
        pthread_mutex_lock(&mutex);//上锁
        printf("t2 pthread:%ld\n",(unsigned long)pthread_self());
        printf("t2 arg2=%d\n",*((int*)arg));
        pthread_mutex_unlock(&mutex);//解锁
}
 
int main(){
    
    
 
        int arg=10;
        int arg2=101;
        pthread_t t1;
        pthread_t t2;
        pthread_mutex_init(&mutex,NULL);//初始化锁,并设置为默认属性    
 
 
        int ret=pthread_create(&t1,NULL,funct1,(void*)&arg);
        int ret2=pthread_create(&t1,NULL,funct2,(void*)&arg2);
 
        printf("main pthread:%ld\n",(unsigned long)pthread_self());
 
        pthread_join(t1,NULL);
        pthread_join(t1,NULL);
 
        pthread_mutex_destroy(&mutex);//销毁锁
 
        for(;;);
        return 0;
}

8.死锁情况

pthread_mutex_t mutex;
pthread_mutex_t mutex2;
 
void* funct1(void* arg){
    
    
 
        pthread_mutex_lock(&mutex);
        sleep(2);
        pthread_mutex_lock(&mutex2);
        static char* ret="you are a lucky dog";
        printf("t1 thread:%ld\n",(unsigned long)pthread_self());
        printf("t1 arg:%d\n",*((int*)arg));
        //int pthread_exit(void *rval_ptr);
        pthread_mutex_unlock(&mutex);
        pthread_mutex_unlock(&mutex2);
        pthread_exit((void*)ret);
}
 
void* funct2(void* arg){
    
    
 
        pthread_mutex_lock(&mutex2);
        sleep(2);
        pthread_mutex_lock(&mutex);
        static char* ret2="you are a single dog";
        printf("t2 thread:%ld\n",(unsigned long)pthread_self());
        printf("t2 arg:%d\n",*((int*)arg));
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex);
        pthread_exit((void*)ret2);
}
 
int main(){
    
    
 
        pthread_t t1;
        pthread_t t2;
        int arg=100;
        int arg2=100;
`       char* pret;
        char* pret2;
 
        pthread_mutex_init(&mutex,NULL);
        pthread_mutex_init(&mutex2,NULL);
 
        int ret=pthread_create(&t1,NULL,funct1,(void*)&arg);
        if(ret == 0){
    
    
                printf("create pthread t1 success!\n");
        }
        int ret2=pthread_create(&t2,NULL,funct2,(void*)&arg2);
        if(ret2 == 0){
    
    
                printf("creat pthread t2 successs!\n");
        }
 
        //int pthread_join(pthread_t thread, void **rval_ptr);
 
        int join=pthread_join(t1,(void**)&pret);
        int join2=pthread_join(t2,(void**)&pret2);
 
        printf("main:%ld\n",(unsigned long)pthread_self());
        printf("pret=%s\n",pret);
        printf("pret2=%s\n",pret2);
 
        pthread_mutex_destroy(&mutex);
        pthread_mutex_destroy(&mutex2);
 
        for(;;);
 
        return 0;
}

9.线程条件实现线程的同步

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
//int pthread_exit(void *rval_ptr)
//int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);//线程条件等待
 
int data=0;
pthread_mutex_t mutex;
pthread_cond_t cond;//创建条件
 
void* funct1(void* arg){
    
    
 
        static char* ret="you are a lucky dog";
        printf("t1 thread:%ld\n",(unsigned long)pthread_self());
        printf("t1 arg:%d\n",*((int*)arg));
        static int cnt=0;
        while(1){
    
    
                pthread_cond_wait(&cond,&mutex);//线程条件等待          
                printf("FUCK YOU!\n");
                printf("t1 data:%d\n",data);
                data=0;
                sleep(1);
                if(cnt++ == 10){
    
    
                        exit(1);
                }
        }
//      pthread_exit((void*)ret);
}
 
void* funct2(void* arg2){
    
    
 
        static char* ret2="you are a single dog";
        printf("t2 thread:%ld\n",(unsigned long)pthread_self());
        printf("t2 arg:%d\n",*((int*)arg2));
        while(1){
    
    
                printf("t2 phtread:%d\n",data);
                pthread_mutex_lock(&mutex);
                data++;
                if(data == 3){
    
    
                        //int pthread_cond_signal(pthread_cond_t *cond);//条件触发
                        pthread_cond_signal(&cond);//条件触发
                }
                pthread_mutex_unlock(&mutex);
                sleep(1);
        }
        //pthread_exit((void*)ret2);
}
 
int main(){
    
    
 
        pthread_t t1;
        pthread_t t2;
        int arg=10;
        int arg2=11;
        char* pret;
        char* pret2;
        pthread_mutex_init(&mutex,NULL);
 
        //int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);//条件初始化
        pthread_cond_init(&cond,NULL);//条件初始化
 
        pthread_create(&t1,NULL,funct1,(void*)&arg);
        pthread_create(&t2,NULL,funct2,(void*)&arg2);
 
        pthread_join(t1,(void**)&pret);
        pthread_join(t2,(void**)&pret2);
 
        printf("pret=%s\n",pret);
        printf("pret2=%s\n",pret2);
 
        pthread_mutex_destroy(&mutex);
 
        //int pthread_cond_destroy(pthread_cond_t cond);//条件销毁
        pthread_cond_destroy(&cond);//销毁条件
 
        return 0;
}

猜你喜欢

转载自blog.csdn.net/zouchengzhi1021/article/details/113178296