




已阅读5页,还剩2页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
进行多线程编程,最头疼的就是那些共享的数据。因为你无法知道哪个线程会在哪个时候对它进行操作,你也无法得知那个线程会先运行,哪个线程会后运行。下面介绍一些技术,通过他们,你会合理安排你的线程之间对资源的竞争。l互斥体Mutexl信号灯Semophorel条件变量Conditions先说一下互斥量。什么时候会用上互斥量了?比如你现在有一全局链表,你有几个工作线程。每一个线程从该链表中取出头节点,然后对该头节点进行处理。比如现在线程1正在取出头节点,他的操作如下:Item * p =queue_list;Queue_list=queue_list-next;Process_job(p);Free(p);当线程1处理完第一步,也就是Item *p=queue_list后,这时候系统停止线程1的运行,改而运行线程2。线程2照样取出头节点,然后进行处理,最后释放了该节点。过了段时间,线程1重新得到运行。而这个时候,其实p所指向的节点已经被线程2释放掉,而线程1对此毫无知晓。他会接着运行process_job(p)。而这将导致无法预料的后果!对于这种情况,系统给我们提供了互斥量。你在取出头节点前必须要等待互斥量,如果此时有其他线程已经获得该互斥量,那么线程将会阻塞在这个地方。只有等到其他线程释放掉该互斥量后,你的线程才有可能得到该互斥量。为什么是可能了?因为可能此时有不止你一个线程在等候该互斥量,而系统无法保证你的线程将会优先运行。互斥量的类型为pthread_mutex_t。你可以声明多个互斥量。在声明该变量后,你需要调用pthread_mutex_init()来创建该变量。pthread_mutex_init的格式如下:intpthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutex-attr_t *mutexattr);第一个参数,mutext,也就是你之前声明的那个互斥量,第二个参数为该互斥量的属性。这个将在后面详细讨论。在创建该互斥量之后,你便可以使用它了。要得到互斥量,你需要调用下面的函数:int pthread_mutex_lock(pthread_mutex_t *mutex);该函数用来给互斥量上锁,也就是我们前面所说的等待操作。互斥量一旦被上锁后,其他线程如果想给该互斥量上锁,那么就会阻塞在这个操作上。如果在此之前该互斥量已经被其他线程上锁,那么该操作将会一直阻塞在这个地方,直到获得该锁为止。在得到互斥量后,你就可以进入关键代码区了。同样,在操作完成后,你必须调用下面的函数来给互斥量解锁,也就是前面所说的释放。这样其他等待该锁的线程才有机会获得该锁,否则其他线程将会永远阻塞。int pthread_mutex_unlock(pthread_mutex_t *mutex);下面给出一个简单的例子:#include #include struct job /* Link field for linked list. */struct job* next;/* Other fields describing work to be done. */;/* A linked list of pending jobs. */struct job* job_queue;/* A mutex protecting job_queue. */pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;/* Process queued jobs until the queue is empty. */void* thread_function (void* arg)while (1) struct job* next_job;/* Lock the mutex on the job queue. */pthread_mutex_lock (&job_queue_mutex);/* Now its safe to check if the queue is empty. */if (job_queue = NULL)next_job = NULL;else /* Get the next available job. */next_job = job_queue;/* Remove this job from the list. */job_queue = job_queue-next;/* Unlock the mutex on the job queue because were done with thequeue for now. */pthread_mutex_unlock (&job_queue_mutex);/* Was the queue empty? If so, end the thread. */if (next_job = NULL)break;/* Carry out the work. */process_job (next_job);/* Clean up. */free (next_job);return NULL;在这个例子中我们使用了下面一条语句:pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;他的作用和调用pthread_mutex_init()函数一样。如果一个线程已经给一个互斥量上锁了,后来在操作的过程中又再次调用了该上锁的操作,那么该线程将会无限阻塞在这个地方,从而导致死锁。怎么变了?这就需要我们之前所提到的互斥量的属性。互斥量分为下面三种:l快速型。这种类型也是默认的类型。该线程的行为正如上面所说的。l递归型。如果遇到我们上面所提到的死锁情况,同一线程循环给互斥量上锁,那么系统将会知道该上锁行为来自同一线程,那么就会同意线程给该互斥量上锁。l错误检测型。如果该互斥量已经被上锁,那么后续的上锁将会失败而不会阻塞,pthread_mutex_lock()操作将会返回EDEADLK。互斥量的属性类型为pthread_mutexattr_t。声明后调用pthread_mutexattr_init()来创建该互斥量。然后调用int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);来设置属性。int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);格式如下:int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);第一个参数,attr,就是前面声明的属性变量,第二个参数,kind,就是我们要设置的属性类型。他有下面几个选项:lPTHREAD_MUTEX_FAST_NPlPTHREAD_MUTEX_RECURSIVE_NPlPTHREAD_MUTEX_ERRORCHECK_NP下面给出一个使用属性的简单过程:pthread_mutex_t mutex;pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);pthread_mutex_init(&mutex,&attr);pthread_mutex_destroy(&attr);前面我们提到在调用pthread_mutex_lock()的时候,如果此时mutex已经被其他线程上锁,那么该操作将会一直阻塞在这个地方。如果我们此时不想一直阻塞在这个地方,那么可以调用下面函数:pthread_mutex_trylock()如果此时互斥量没有被上锁,那么pthread_mutex_trylock()将会返回0,并会对该互斥量上锁。如果互斥量已经被上锁,那么会立刻返回EBUSY。上面谈到的是使用互斥量。如果碰到下面这种情况,该怎么办了?还是上面程序中提到的工作链表。此时必然有一个生产者线程,用于往链表里添加节点。如果这一段时间没有工作,那么工作线程将会不停的调用lock,unlock操作。而这样的操作毫无疑义。在这里系统给我们提供了另外一种同步机制,信号灯,Semaphore。信号灯其实就是一个计数器,也是一个整数。每一次调用wait操作将会使semaphore值减一,而如果semaphore值已经为0,则wait操作将会阻塞。每一次调用post操作将会使semaphore值加一。将这些操作用到上面的问题中。工作线程每一次调用wait操作,如果此时链表中没有节点,则工作线程将会阻塞,直到链表中有节点。生产者线程在每次往链表中添加节点后调用post操作,信号灯值会加一。这样阻塞的工作线程就会停止阻塞,继续往下执行。信号灯的类型为sem_t。在声明后必须调用sem_init()。需要传递两个参数,第一个参数就是你之前声明的sem_t变量,第二个必须为0。当你不再需要信号灯时,你必须调用sem_destroy()来释放资源。等待信号灯的操作为sem_wait()。投递一个信号的操作为sem_wait()。和互斥量一样,等待信号灯也有一个非阻塞的操作,sem_trywait()。该操作在没有信号灯的时候返回EAGAIN。下面是一个结合了互斥量和信号灯的例子:#include #include #include struct job /* Link field for linked list. */struct job* next;/* Other fields describing work to be done. */;/* A linked list of pending jobs. */struct job* job_queue;/* A mutex protecting job_queue. */pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;/* A semaphore counting the number of jobs in the queue. */sem_t job_queue_count;/* Perform one-time initialization of the job queue. */void initialize_job_queue ()/* The queue is initially empty. */job_queue = NULL;/* Initialize the semaphore which counts jobs in the queue. Itsinitial value should be zero. */sem_init (&job_queue_count, 0, 0);/* Process queued jobs until the queue is empty. */void* thread_function (void* arg)while (1) struct job* next_job;/* Wait on the job queue semaphore. If its value is positive,indicating that the queue is not empty, decrement the count by1. If the queue is empty, block until a new job is enqueued. */sem_wait (&job_queue_count);/* Lock the mutex on the job queue. */pthread_mutex_lock (&job_queue_mutex);/* Because of the semaphore, we know the queue is not empty. Getthe next available job. */next_job = job_queue;/* Remove this job from the list. */job_queue = job_queue-next;/* Unlock the mutex on the job queue because were done with thequeue for now. */pthread_mutex_unlock (&job_queue_mutex);/* Carry out the work. */process_job (next_job);/* Clean up. */free (next_job);return NULL;/* Add a new job to the front of the job queue. */void enqueue_job (/* Pass job-specific data here. */)struct job* new_job;/* Allocate a new job object. */new_job = (struct job*) malloc (sizeof (struct job);/* Set the other fields of the job struct here. */* Lock the mutex on the job queue before accessing it. */pthread_mutex_lock (&job_queue_mutex);/* Place the new job at the head of the queue. */new_job-next = job_queue;job_queue = new_job;/* Post to the semaphore to indicate that another job is available. Ifthreads are blocked, waiting on the semaphore, one will becomeunblocked so it can process the job. */sem_post (&job_queue_count);/* Unlock the job queue mutex. */pthread_mutex_unlock (&job_queue_mutex);下面说一下第三种同步机制条件变量。如果现在在等待一个信号。如果该信号被设置,则继续运行。如果没有条件变量,我们将会不停的去查询该信号是否被设置,这样就会浪费大量的cpu。而通过使用条件变量,我们就可以将等待信号的线程阻塞,直到有信号的时候再去唤醒它。条件变量的类型是pthread_cond_t。下面简单说一下如何使用条件变量。l声明pthread_cond_t变量后,调用pthread_cond_init()函数,第一个参数为之前声明的变量。第二个参数在Linux中不起作用。l声明一个pthread_mutex_t变量
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高铁预制箱梁施工课件
- 济南市2024-2025学年七年级下学期语文期中测试试卷
- 济南市2025-2026学年八年级上学期语文月考模拟试卷
- 高速路政日常工作课件
- 电芯销售知识培训内容课件
- 电脑知识应用培训记录课件
- 高考改革课件
- SGLT-2 抑制剂作用机制试卷及答案
- 电网廉洁从业课件
- 广西河池市凤山县2022-2023学年九年级上学期期中化学试题(含答案)
- 测绘地理信息从业人员保密知识培训
- 医院行风岗前培训
- 智慧水利方案介绍课件(共31张课件)
- 《数据采集系统》课件
- 2024-2030年中国眼镜盒市场发展趋势及前景规划调研报告
- 压疮的预防管理制度
- 危重病人体位管理
- 第八章新时代坚持和发展中国特色社会主义的重要保障-2024版研究生新中特教材课件
- (新版)六西格玛黄带认证考试复习题库(含答案)
- 电子元器件检测与筛选手册
- 九年级化学上册开学第一课人教版2024化学
评论
0/150
提交评论