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)
线程同步有几种实现方法,都是什么?答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口
同步的实现方面有两种,分别是synchronized,wait与notify
线程同步的几种方法的总结
线程同步的方式包括:互斥锁、读写锁、条件变量、信号量和令牌。互斥锁和读写锁:提供对临界资源的保护,当多线程试图访问临界资源时,都必须通过获取锁的方式来访问临界资源。(临界资源:是被多线程共享的资源)当读写线程获取锁的频率差别不大时,一般采用互斥锁,如果读线程访问临界资源的频率大于写线程,这个时候采用读写锁较为合适,读写锁允许多个读线程同时访问临界资源,读写线程必须互斥访问临界资源。读写锁的实现采用了互斥锁,所以在读写次数差不多的情况下采用读写锁性能没有直接采用互斥锁来的高。条件变量:提供线程之间的一种通知机制,当某一条件满足时,线程A可以通知阻塞在条件变量上的线程B,B所期望的条件已经满足,可以解除在条件变量上的阻塞 *** 作,继续做其他事情。信号量:提供对临界资源的安全分配。如果存在多份临界资源,在多个线程争抢临界资源的情况下,向线程提供安全分配临界资源的方法。如果临界资源的数量为1,将退化为锁。令牌:一种高级的线程同步的方法。它既提供锁的安全访问临界资源的功能,又利用了条件变量使得线程争夺临界资源时是有序的。下面提供Token在ACE中的一种实现方法。可以从下面的类图,可以看到ACE是如何设计Token的。 ACE_Token:这个类是Token类,提供了获取和释放Token的方法。对于Token的获取策略,ACE提供两种实现:FIFO和LIFO。Token中对应着两个队列,一个是获取Token是为了写的队列,另外一个是获取Token是为了读的队列。ACE_Token_Queue:队列是一个链表,该类提供对链表的管理 *** 作。ACE_Token_Entry:是队列中存放的元素,提供了对条件变量的封装,一个元素代表一个线程试图获取Token。如果Token已经被获取,线程需要阻塞在自己的Token上(队列Entry中的条件变量上)。等待Token持有者释放该Token,并通知阻塞的线程。 下面对ACE_Token中的组要方法提供分析。 获取判断是否有线程已经持有互斥锁了,如果没人持有,表示临界资源是可用的,那么可以立即返回成功。检查是不是线程尝试递归获取互斥锁。因为Token支持这种情况,所以也可立即返回成功。同时将nesting计数器自增。创建一个Token Entry,并将其排入队列。调用用户自定义的Hook方法,在线程进行sleep之前,用户可以调用自定义的Hook方法。线程睡眠,如果线程唤醒后,发现当前线程不是Token的拥有者将继续睡眠。线程被唤醒后,将Token entry从队列中删除。释放如果发现嵌套层数大于0,需要将嵌套层数的计数器减一,然后让该线程继续持有Token。否则,该线程负责从队列中按照一定的策略,取出Token entry,并通过该Entry通知阻塞在Entry上的线程,资源被释放,你可以使用资源了。
请用技术语言介绍下线程同步,并发 *** 作怎么控制
现在流行的进程线程同步互斥的控制机制,其实是由最原始最基本的4种方法实现的。由这4种方法组合优化就有了.Net和Java下灵活多变的,编程简便的线程进程控制手段。
这4种方法具体定义如下 在《 *** 作系统教程》ISBN 7-5053-6193-7 一书中可以找到更加详细的解释
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
2、互斥量:为协调共同对一个共享资源的单独访问而设计的。
3、信号量:为控制一个具有有限数量用户资源而设计。
4、事 件:用来通知线程有一些事件已发生,从而启动后继任务的开始。
临界区(Critical Section)
保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式 *** 作共享资源的目的。
临界区包含两个 *** 作原语:
EnterCriticalSection() 进入临界区
LeaveCriticalSection() 离开临界区
EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。
MFC提供了很多功能完备的类,我用MFC实现了临界区。MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。
CriticalSection
CCriticalSection global_CriticalSection
共享资源
char global_Array[256]
初始化共享资源
void InitializeArray()
{
for(int i = 0i<256i++)
{
global_Array[i]=I
}
}
写线程
UINT Global_ThreadWrite(LPVOID pParam)
{
CEdit *ptr=(CEdit *)pParam
ptr->SetWindowText("")
进入临界区
global_CriticalSection.Lock()
for(int i = 0i<256i++)
{
global_Array[i]=W
ptr->SetWindowText(global_Array)
Sleep(10)
}
离开临界区
global_CriticalSection.Unlock()
return 0
}
删除线程
UINT Global_ThreadDelete(LPVOID pParam)
{
CEdit *ptr=(CE......>>
C语言怎么实现多线程同步
使用pthread库执行多线程,这个是Linux下的线程库 Windows下应该有自己的API,不过这种东西一般还是以Linux为标准。pthread_create()创建一个线程,传入fun()的函数指针就行了。
然后这个Beep()的需求要进行线程间通信,可以用共享内存的方法,设一个bool变量flag共享,然后beep的时候设为false,beep完设成true。fun()里面每次看一下这个flag,是false的话就不做动作等下一秒,基本可以满足需求。
这样做的好处是实现简单,但时间是以1s为单位的。如果要8秒结束立刻执行,需要用条件变量的方法来控制,比较复杂,这样的实现方式一个可以满足需求了。
Java线程同步的方法
等待唤醒机制
wait():让线程等待。将线程存储到一个线程池中。
notify():唤醒被等待的线程。通常都唤醒线程池中的第一个。让被唤醒的线程处于临时阻塞状态。
notifyAll(): 唤醒所有的等待线程。将线程池中的所有线程都唤醒,让它们从冻结状体转到临时阻塞状态.
这三个方法用于 *** 作线程,可是定义在了Object类中,为什么呢?
因为,这三个方法在使用时,都需要定义在同步中,要明确这些方法所 *** 作的线程所属于锁。
简单说。在A锁被wait的线程,只能被A锁的notify方法唤醒。
所以必须要表示wait notify方法所属的锁对象,而锁对象可以是任意的对象。
可以被任意的对象调用的方法肯定弧义在Object类中。
注意:等待唤醒机制,通常都用在同步中,因为需要锁的支持。
而且必须要明确wait notify 所作用的锁对象。
JDK1.5后的锁
在jdk1.5版本之后,
出现了一些新的特性,将原理的线程进行了改良。
在java.util.concurrent.locks包中提供了一个接口Lock。替代了synchronized。
synchronized。使用的是锁 *** 作是隐式的。
Lock接口,使用的锁 *** 作是显示的。
由两个方法来完成:
lock():获取锁。
unlock():释放锁。
还有一个对象,Condition.
该对象的出现替代了Object中的wait notify notifyAll这些 *** 作监视器的方法。
替代后的方式:await signal signalAll.
线程同步互斥的4种方式
临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4、事 件: 通过通知 *** 作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的 *** 作
如何实现序列化?如何实现线程的同步
在java5以前实现多线程有两种方法(继承Thread类和实现Runnable接口)
它们分别为:
使用new Thread()和new Thread(Runnable)形式
第一种直接调用thread的run方法,所以,往往使用Thread子类,即new SubThread()。
第二种调用
Runnable的run方法。
第一种:
new Thread(){}.start()这表示调用Thread子类对象的run方法,new Thread(){}表示一个Thread的匿名子类的实例对象,子类加上run方法后的代码如下:
new Thread(){
public void run(){
}
}.start()
第二种:
new Thread(
new Runnable(){}
).start()
这表示调用Thread对象接受的Runnable对象的run方法,new Runnable(){}表示一个Runnable的匿名子类的实例对象,
runnable的子类加上run方法后的代码如下:
new Thread(new Runnable(){
public void run(){
}
}
).start()
线程同步有几种实现方法,都是什么
继承Thread 类与实现Runnable 接口都能实现多线程
synchronized,wait 与notify 可以实现同步
实现线程同步的话在java中可以怎么实现
用synchronize关键字,可以有代码段加锁,对象加锁,方法加锁等方法实现线程同步
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)