linux 线程 pthread(linux makefile文件)

大家好,如果您还对linux 线程 pthread不太了解,没有关系,今天就由本站为大家分享linux 线程 pthread的知识,包括linux makefile文件的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!

Linux线程及同步

linux多线程

1.线程概述

线程是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。一个进程可以有多个线程,也就

是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。

2.线程实现

线程创建pthread_create()

所需头文件#include

<pthread.h>

函数原型int

pthread_create

((pthread_t

*thread,

pthread_attr_t

*attr,

thread:线程标识符

attr:线程属性设置

start_routine:线程函数的起始地址

arg:传递给start_routine的参数

函数返回值

成功:0

出错:-1

线程退出pthread_exit();

所需头文件#include

<pthread.h>

函数原型void

pthread_exit(void

*retval)

函数传入值retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join

来检索获取

等待线程退出并释放资源pthread_join()

所需头文件#include

<pthread.h>

函数原型int

pthread_join

((pthread_t

th,

void

**thread_return))

函数传入值

th:等待线程的标识符

thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)

函数返回值

成功:0

出错:-1

代码举例

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

/*线程1*/

6.

void

thread1()

7.

{

8.

int

i=0;

9.

10.

while(1)

11.

{

12.

printf(thread1:%d/n,i);

13.

if(i>3)

14.

pthread_exit(0);

15.

i++;

16.

sleep(1);

17.

}

18.

}

19.

20.

/*线程2*/

21.

void

thread2()

22.

{

23.

int

i=0;

24.

25.

while(1)

26.

{

27.

printf(thread2:%d/n,i);

28.

if(i>5)

29.

pthread_exit(0);

30.

i++;

31.

sleep(1);

32.

}

33.

}

34.

35.

int

main()

36.

{

37.

pthread_t

t1,t2;

38.

39.

/*创建线程*/

40.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

41.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

42.

/*等待线程退出*/

43.

pthread_join(t1,NULL);

44.

pthread_join(t2,NULL);

45.

return

0;

46.

}

3同步与互斥

<1>互斥锁

互斥锁的操作主要包括以下几个步骤。

互斥锁初始化:pthread_mutex_init

互斥锁上锁:pthread_mutex_lock

互斥锁判断上锁:pthread_mutex_trylock

互斥锁接锁:pthread_mutex_unlock

消除互斥锁:pthread_mutex_destroy

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

int

i=0;/*共享变量*/

6.

pthread_mutex_t

mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥锁*/

7.

8.

void

thread1()

9.

{

10.

int

ret;

11.

while(1)

12.

{

13.

14.

15.

ret=pthread_mutex_trylock(&mutex);/*判断上锁*/

16.

17.

if(ret!=EBUSY)

18.

{

19.

pthread_mutex_lock(&mutex);/*上锁*/

20.

printf(This

is

thread1:%d/n,i);

21.

i++;

22.

pthread_mutex_unlock(&mutex);/*解锁*/

23.

}

24.

sleep(1);

25.

}

26.

}

27.

28.

void

thread2()

29.

{int

ret;

30.

while(1)

31.

{

32.

33.

ret=pthread_mutex_trylock(&mutex);

34.

if(ret!=EBUSY)

35.

{

36.

pthread_mutex_lock(&mutex);

37.

printf(This

is

thread2:%d/n,i);

38.

i++;

39.

pthread_mutex_unlock(&mutex);

40.

}

41.

sleep(1);

42.

}

43.

}

44.

int

main()

45.

{

46.

pthread_t

t1,t2;

47.

pthread_mutex_init(&mutex,NULL);

48.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

49.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

50.

51.

pthread_join(t1,NULL);

52.

pthread_join(t2,NULL);

53.

54.

pthread_mutex_destroy(&mutex);

55.

return

0;

56.

}

<2>信号量

未进行同步处理的两个线程

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

int

i=0;

6.

void

thread1()

7.

{

8.

9.

while(1)

10.

{

11.

printf(This

is

thread1:%d/n,i);

12.

i++;

13.

sleep(1);

14.

}

15.

}

16.

17.

18.

void

thread2()

19.

{

20.

21.

while(1)

22.

{

23.

printf(This

is

thread2:%d/n,i);

24.

i++;

25.

sleep(1);

26.

}

27.

}

28.

29.

int

main()

30.

{

31.

pthread_t

t1,t2;

32.

33.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

34.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

Linux 多线程编程(二)2019-08-10

三种专门用于线程同步的机制:POSIX信号量,互斥量和条件变量.

在Linux上信号量API有两组,一组是System V IPC信号量,即PV操作,另外就是POSIX信号量,POSIX信号量的名字都是以sem_开头.

phshared参数指定信号量的类型,若其值为0,就表示这个信号量是当前进程的局部信号量,否则该信号量可以在多个进程之间共享.value值指定信号量的初始值,一般与下面的sem_wait函数相对应.

其中比较重要的函数sem_wait函数会以原子操作的方式将信号量的值减一,如果信号量的值为零,则sem_wait将会阻塞,信号量的值可以在sem_init函数中的value初始化;sem_trywait函数是sem_wait的非阻塞版本;sem_post函数将以原子的操作对信号量加一,当信号量的值大于0时,其他正在调用sem_wait等待信号量的线程将被唤醒.

这些函数成功时返回0,失败则返回-1并设置errno.

生产者消费者模型:

生产者对应一个信号量:sem_t producer;

消费者对应一个信号量:sem_t customer;

sem_init(&producer,2)----生产者拥有资源,可以工作;

sem_init(&customer,0)----消费者没有资源,阻塞;

在访问公共资源前对互斥量设置(加锁),确保同一时间只有一个线程访问数据,在访问完成后再释放(解锁)互斥量.

互斥锁的运行方式:串行访问共享资源;

信号量的运行方式:并行访问共享资源;

互斥量用pthread_mutex_t数据类型表示,在使用互斥量之前,必须使用pthread_mutex_init函数对它进行初始化,注意,使用完毕后需调用pthread_mutex_destroy.

pthread_mutex_init用于初始化互斥锁,mutexattr用于指定互斥锁的属性,若为NULL,则表示默认属性。除了用这个函数初始化互斥所外,还可以用如下方式初始化:pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER。

pthread_mutex_destroy用于销毁互斥锁,以释放占用的内核资源,销毁一个已经加锁的互斥锁将导致不可预期的后果。

pthread_mutex_lock以原子操作给一个互斥锁加锁。如果目标互斥锁已经被加锁,则pthread_mutex_lock则被阻塞,直到该互斥锁占有者把它给解锁.

pthread_mutex_trylock和pthread_mutex_lock类似,不过它始终立即返回,而不论被操作的互斥锁是否加锁,是pthread_mutex_lock的非阻塞版本.当目标互斥锁未被加锁时,pthread_mutex_trylock进行加锁操作;否则将返回EBUSY错误码。注意:这里讨论的pthread_mutex_lock和pthread_mutex_trylock是针对普通锁而言的,对于其他类型的锁,这两个加锁函数会有不同的行为.

pthread_mutex_unlock以原子操作方式给一个互斥锁进行解锁操作。如果此时有其他线程正在等待这个互斥锁,则这些线程中的一个将获得它.

三个打印机轮流打印:

输出结果:

如果说互斥锁是用于同步线程对共享数据的访问的话,那么条件变量就是用于在线程之间同步共享数据的值.条件变量提供了一种线程之间通信的机制:当某个共享数据达到某个值时,唤醒等待这个共享数据的线程.

条件变量会在条件不满足的情况下阻塞线程.且条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生.

其中pthread_cond_broadcast函数以广播的形式唤醒所有等待目标条件变量的线程,pthread_cond_signal函数用于唤醒一个等待目标条件变量线程.但有时候我们可能需要唤醒一个固定的线程,可以通过间接的方法实现:定义一个能够唯一标识目标线程的全局变量,在唤醒等待条件变量的线程前先设置该变量为目标线程,然后采用广播的方式唤醒所有等待的线程,这些线程被唤醒之后都检查该变量以判断是否是自己.

采用条件变量+互斥锁实现生产者消费者模型:

运行结果:

阻塞队列+生产者消费者

运行结果:

有人能教下我有关linux里面线程的知识吗

.线程的基本介绍

(1)线程的概述

线程与进程类似,也允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程,同一程序中的所有线程共享同一份全局内存区域,线程之间没有真正意义的等级之分。同一个进程中的线程可以并发执行,如果处理器是多核的话线程也可以并行执行,如果一个线程因为等待I/O操作而阻塞,那么其他线程依然可以继续运行

(2)线程优于进程的方面

argv,environ

主线程栈

线程3的栈

线程2的栈

线程1的栈

共享函数库共享的内存

未初始化的数据段

初始化数据段

文本

.进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通讯,在进程之间交换信息

.调用fork()来创建进程代价相对较高

线程很好的解决了上述俩个问题

.线程之间能够方便,快速的共享信息,只需将数据复制到共享(全局或堆)变量中即可

.创建线程比创建线程通常要快10甚至更多,线程创建之所以快,是因为fork创建进程时所需复制多个属性,而在线程中,这些属性是共享的。

(3)创建线程

启动程序时,产生的进程只有单条线程,我们称之为主线程

#include<pthread.h>

int pthread_create(pthread_t*thread,const pthread_attr_t*attr,void*(*start)(void*),void*arg);12

新线程通过调用带有arg的函数开始执行,调用pthread_create()的线程会继续执行该调用之后的语句。

(4)终止线程

可以以如下方式终止线程的运行

.线程调用pthread_exit()

.线程start函数执行return语句并返回指定值

.调用pthread_cancel()取消线程

.任意线程调用了exit(),或者主线程执行了return语句,都会导致进程中的所有线程立即终止

pthread_exit()函数可以终止线程,且其返回值可由另一线程通过调用pthread_join()获得

#include<pthread.h>void pthread_exit(void*retval);12

调用pthread_exit()相当于在线程的start函数中执行return,不同之处在于,pthread_exit()可以在任何地方调用,参数retval指定了线程的返回值

(5)获取线程ID

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

线程ID在应用程序中主要有如下用途

.不同的pthreads函数利用线程ID来标识要操作目标线程。

.在具体的应用程序中,以特定线程的线程ID作为动态数据结构的标签,这颇有用处,既可用来识别某个数据结构的创建者或属主线程,又可确定随后对该数据结构执行操作的具体线程

函数pthread_equal()可检查俩个线程的ID是否相同

#include<pthread.h>int pthread_equal(pthread_t t1,pthread_t t2);//如果相同返回非0值,否则返回0123

(6)连接已终止的线程

函数pthread_join()等待由thread表识的线程终止

#include<pthread.h>int pthread_join(pthread_t thread,void**retval);//返回0调用成功,否则失败123

如果pthread_join()传入一个之前已然连接过的线程ID,将会导致无法预知的行为,当相同线程ID在参与一次连接后恰好为另一新建线程所重用,再度连接的可能就是这个新线程

若线程未分离,则就应该使用pthread_join()来连接线程,否则会产生僵尸线程

pthrea_join()函数的要点

.线程之间的关系是对等的,所以任意线程都可以调用pthread_join()来连接其他线程

.pthread_join()无法针对任意线程,只能连接单个线程

(6)线程的分离

默认情况下线程都是可连接的,但有时候,我们并不关心线程退出的状态,我们可以调用pthread_detach()并向thread参数传入指定线程的的标识符,将该线程标记为处于分离状态

#include<pthread.h>int pthread_detach(pthread_t thread);//返回0成功,否则失败123

一旦线程处于分离状态,就不能在使用pthread_join()来获取其状态,也无法使其重返可连接状态

(7)在应用程序中如何来选择进程还是线程

.线程之间共享数据很简单,进程间的数据共享需要更多的投入

.创建线程要比创建进程块很多

.多线程编程时,需要确保调用线程安全的函数

.某个线程中的bug可能会危害进程中所有线程

.每个线程都在征用宿主进程中有限的虚拟地址空间

.在多线程应用中,需要小心使用信号

.除了数据,线程还可以共享文件描述符,信号处置,当前工作目录,以及用户ID和组ID

线程的同步

(1)保护共享变量访问:互斥量

线程的主要优势在于能够通过全局变量来共享信息,不过这种共享是有代价的。必须确保多个线程修改同一变量时,不会有其他线程也正在修改此变量,为避免线程更新时共享变量时所出现的问题,必须使用互斥量来确保同时仅有一个线程可以访问某项共享资源

(2)静态分配的互斥锁

互斥锁既可以像静态变量那样分配,也可以在运行时动态分配,互斥量属于pthread_mutex_t类型的变量,在使用之前必须对其初始化。对于静态分配的互斥量而言,可如下例所示,将PTHREAD_MUTEX_INITIALIZER赋给互斥量

pthread_mutex_t= PTHREAD_MUTEX_INITIALIZER;1

1.加锁和解锁互斥量

初始化之后,互斥量处于未锁定状态。函数pthread_mutex_lock()可以锁定某一互斥量

而函数pthread_mutex_unlock()则可以将一个互斥量解锁

#include<pthread.h>int pthread_mutex_lock(pthread_mutex_t*mutex);int pthread_mutex_unlock(pthread_mutex_t*mutex);//返回0成功,其他失败1234

要锁定互斥量,在调用pthread_mutex_lock()时需要指定互斥量,如果互斥量当前处于未锁定状态,则该调用将会立即返回,如果该互斥量已被其他线程锁定,那么该调用将会阻塞,直至互斥量被解锁

函数pthread_mutex_unlock()将解锁之前已遭调用线程锁定的互斥量

2.互斥量的性能

通常情况下,线程会花费更多的时间去做其他工作,对互斥量的加锁解锁相对要少的多,因此使用互斥量对大部分程序来说性能并无显著的影响

3.互斥量的死锁

当一个线程需要同时访问多个共享资源时,没个资源由不同的互斥索管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁。如下图所示

线程A

1.pthread_mutex_lock(mutex1);

2.pthread_mutex_lock(mutex2);

线程2

1.pthread_mutex_lock(mutex2);

2.pthread_mutex_lock(mutex1);

每个线程都成功的锁住一个互斥量,接着试图对以为另一线程锁定的互斥量加锁,就会一直等下去

要避免此类死锁问题,最简单的就是定义互斥量的层级关系

阅读剩余
THE END