linux系统编程(线程)

参考:(5条消息) linux笔记:线程_转角心静了的博客-CSDN博客

一、线程的引入

  1. 线程与进程的区别

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

根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位

2、线程的优势

(1)易于调度。

(2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。

(3)开销少。创建线程比创建进程要快,所需开销很少。。

(4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。

二、线程

线程的创建:pthread_create函数

 #include <pthread.h>
int pthread_create(
//pthread_t表示线程的数据类型,这里传递一个 pthread_t 类型的指针变量,也可直接传递某个 pthread_t 类型变量的地址
                   pthread_t *thread,
//用于手动设置新建线程的属性,这里赋值赋值为 NULL,会采用系统默认的属性值创建线程。
                   const pthread_attr_t *attr,
//以函数指针的方式指明新建线程需要执行的函数,形参和返回值的类型都必须为 void* 类型。
                   void *(*start_routine) (void *), 
//指定传递给 start_routine 函数的实参,当不需要传递任何数据时,将 arg 赋值为 NULL 即可。
                   void *arg);


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

线程的退出:pthread_exit函数

#include <pthread.h>
int pthread_exit(void *rval_ptr);
//retval 是 void* 类型的指针,可以指向任何类型的数据,它指向的数据将作为线程退出时的返回值。如果线程不需要返回任何数据,将 retval 参数置为 NULL 即可。

进程中的其他线程可以通过调用pthread_join函数访问到这个指针。

线程的等待:pthread_join函数

#include <pthread.h>
                        //thread 参数用于指定接收哪个线程的返回值;rval 参数表示接收到的返回值,如果 thread 线程没有返回值,又或者我们不需要接收 thread 线程的返回值,可以将 retval 参数置为 NULL。

int pthread_join(pthread_t thread, void **rval_ptr);

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

调用pthread_join() 函数会一直阻塞调用它的线程,直至目标线程执行结束(接收到目标线程的返回值),阻塞状态才会解除。如果 pthread_join() 函数成功等到了目标线程执行结束(成功获取到目标线程的返回值),返回值为数字 0;反之如果执行失败,函数会根据失败原因返回相应的非零值,每个非零值都对应着不同的宏,例如:

  • EDEADLK:检测到线程发生了死锁。

  • EINVAL:分为两种情况,要么目标线程本身不允许其它线程获取它的返回值,要么事先就已经有线程调用 pthread_join() 函数获取到了目标线程的返回值。

  • ESRCH:找不到指定的 thread 线程。

以上这些宏都声明在 <errno.h> 头文件中,如果程序中想使用这些宏,需提前引入此头文件。

查看线程的ID:pthread_self函数

#include <pthread.h>
pthread_t pthread_self(void);
// 返回:调用线程的ID

线程的比较:pthread_equal函数

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
// 返回:若相等则返回非0值,否则返回0

线程的脱离:pthread_detach函数

#include <pthread.h>
int pthread_detach(pthread_t thread);//eg:pthread_detach(pthread_self())
// 返回:若成功返回0,否则返回错误编号

三、互斥锁(mutex)

互斥锁的引入:

Linux中提供一把互斥锁,每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁,

同一时刻,只能有一个线程持有该锁,对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为可运行状态的线程可以对互斥量加锁,其他线程将会看到互斥锁依然被锁住,只能回去等待它重新变为可用。在这种方式下,每次只有一个线程可以向前运行。

补充:死锁情况,死锁发生的前提条件是有至少两把锁,线程A拿到了锁1的时候想要去拿锁2,线程B拿到了锁2的时候想要去拿锁1,此时就会造成死锁的情况。

创建与销毁互斥锁:pthread_mutex_init函数和pthread_mutex_destroy函数

在使用互斥变量前必须对它进行初始化,有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下

#include <pthread.h>

//参数attr指定了新建互斥锁的属性。如果参数attr为空(NULL),则使用默认的互斥锁属性,默认属性为快速互斥锁 

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

//销毁一个互斥锁即意味着释放它所占用的资源,且要求锁当前处于开放状态。
int pthread_mutex_destroy(pthread_mutex_t mutex);

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

加锁与解锁:pthread_mutex_lock函数、pthread_mutex_trylock函数、pthread_mutex_unlock函数

#include <pthread.h>

// pthread_mutex_lock()函数锁住由mutex指定的mutex 对象。如果mutex已经被锁住,调用这个函数的线程阻塞直到mutex可用为止。这跟函数返回的时候参数mutex指定的mutex对象变成锁住状态, 同时该函数的调用线程成为该mutex对象的拥有者。
int pthread_mutex_lock(pthread_mutex_t mutex);

//  pthread_mutex_trylock()调用在参数mutex指定的mutex对象当前被锁住的时候立即返回,除此之外,和上面lock完全一样。
int pthread_mutex_trylock(pthread_mutex_t mutex);

//pthread_mutex_unlock()函数释放有参数mutex指定的mutex对象的锁。
int pthread_mutex_unlock(pthread_mutex_t mutex);
四、条件变量

条件变量的引入

条件变量是线程另一可用的同步机制,条件变量给多个线程提供了一个会合的场所,条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。

创建与销毁条件: pthread_cond_init和pthread_cond_destroy函数

条件变量使用之前必须首先初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_destroy函数对条件变量进行去除初始(deinitialize)。

#include <pthread.h>

//当参数cattr为空指针时,函数创建的是一个缺省的条件变量。
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

int pthread_cond_destroy(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号

等待条件变量:pthread_cond_wait 和pthread_cond_timedwait函数

pthread_cond_wait等待条件变为真,pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数类似,只是多了一个timeout。timeout指定了等待的时间,它是通过timespec结构指定。

#include<pthread.h>

//第一个参数就是条件变量,而第二个参数mutex是保护条件变量的互斥量。也就是说这个函数在使用的时候需要配合pthread_mutex_lock()一起使用。
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);

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

触发条件变量:pthread_cond_signal 和pthread_cond_broadcast函数

这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。

#include<pthread.h>
int pthread_cond_signal(pthread_cond_t cond);
int pthread_cond_broadcast(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号
五、编程实现

线程的创建应用

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


//int  pthread_create((pthread_t  *thread,  pthread_attr_t  *attr,  void  *(*start_routine)(void  *)
,  void  *arg)
void *func1(void *arg)
{

        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());//打印创建线程ID
        printf("t1 param is %d\n",*((int *)arg));//先将arg转换为int *型再取内容
}
int main()
{

        int ret;
        int param=100;//指定传递给 start_routine 函数的实参
        pthread_t t1;

        ret= pthread_create(&t1,NULL,func1,(void *)&param);//创建线程调用func1函数
        if(ret ==0){

                printf("main:create t1 success\n");//创建成功调试信息
        }

        printf("main: %ld\n",(unsigned long)pthread_self());
        pthread_join(t1,NULL);//等待线程
        return 0;
}
#include<stdio.h>
#include <pthread.h>


//int  pthread_create((pthread_t  *thread,  pthread_attr_t  *attr,  void  *(*start_routine)(void  *)
,  void  *arg)
void *func1(void *arg)
{
        static int ret =10;//注意要使用static定义为静态变量,否则在join时会出错

        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);//线程退出时的返回值为p
}
int main()
{

        int ret;
        int param=100;
        pthread_t t1;

        char *pret;
        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);//等待线程,获取返回值pret

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

给线程加锁

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

//int  pthread_create((pthread_t  *thread,  pthread_attr_t  *attr,  void  *(*start_routine)(void  *)
,  void  *arg)

int g_data=0;//定义一个全局变量

pthread_mutex_t mutex;//定义互斥锁
void *func1(void *arg)
{


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

        pthread_mutex_lock(&mutex);//给互斥锁上锁
        while(1){

                printf("t1: %d\n",g_data++);//g_data自加
                sleep(1);
                       // 判定条件   
                if(g_data == 3){

                        pthread_mutex_unlock(&mutex);//g_data满足3,解开互斥锁
                        printf("--------------------------------\n");
//                      pthread_exit(NULL);//退出线程
                        exit(0);//终止程序
                }
        }

}
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);//这里线程2会拿不到锁,没办法进行数据操作
                g_data++;
                pthread_mutex_unlock(&mutex);
                sleep(1);
        }
}
int main()
{

        int ret;
        int param=100;
        pthread_t t1;
        pthread_t t2;

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

        ret= pthread_create(&t1,NULL,func1,(void *)&param);//创建线程t1
        if(ret ==0){

                printf("main:create t1 success\n");
        }

        ret= pthread_create(&t2,NULL,func2,(void *)&param);//创建线程t2
        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);

        pthread_mutex_destroy(&mutex);//销毁互斥锁
        return 0;

}
            

有锁和条件的一个完整线程:只有g_data为3时,线程t1才执行:

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

//int  pthread_create((pthread_t  *thread,  pthread_attr_t  *attr,  void  *(*start_routine)(void  *)
,  void  *arg)

int g_data=0;

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

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);
                }
        }

}
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;
        pthread_t t2;

        pthread_mutex_init(&mutex,NULL);
        pthread_cond_init(&cond,NULL);

        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());


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

        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);//销毁条件变量
        return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值