线程同步问题实例
2015-09-22 13:00
204 查看
1.有一个队列,线程1负责从网络接收分组,并将收到的分组放到队列尾,然后再次从网络中接收下一个到达的分组,并进行同样的队列操作。线程2从此队列头中取出一个分组进行处理,处理完毕后,再次从队列中取出一个分组进行处理,处理完毕后再次从队列头取出下一个分组进行处理,两个线程都以无限循环的方式工作,因此该队列为临时资源,若队列不为空,线程2才应该开始循环处理,否则需要等待,显然如果线程2不停的检测队列是否为空,虽然能够正常工作,但是很消耗cpu资源,cpu效率低,当队列为空时,线程2进入休眠状态,当队列不为空时,线程2自动被唤醒,可以利用条件变量解决这个问题。
函数说明:
[cpp]
view plaincopyprint?
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
返回值:0代表成功,错误号代表失败
参数mutex对条件句进行保护,线程2自动把加锁的互斥量传给此函数,函数把线程2放到等待条件的线程列表上,然后对互斥量进行自动解锁,这两步操作属于原子操作,这样就不会造成条件检查和线程进入休眠状态等待之间有其它线程进入的问题,当线程2因条件不满足而进入休眠后,因为互斥量已经被解锁,于是线程1就可以加锁互斥量并将收到的分组放到队列尾,然后主动解锁互斥量,接着线程1再调用下面的pthread_cond_signal函数通知线程2条件已经发生变化。
[cpp]
view plaincopyprint?
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
返回值:0代表成功,错误号代表失败。
由于此条件发生了改变,则pthread_cond_wait函数返回,保护条件的互斥量将再次被自动加锁(注意这里是自动加锁,不需要线程2主动加锁),线程2被唤醒,于是就可以对临界资源进行操作,即线程2从队列中取出下一个分组并主动对互斥量进行解锁,之后再对该分组进行后续的处理。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <time.h>
std::queue<int>q;
//静态初始化互斥量
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//静态初始化条件变量
pthread_cond_t condition=PTHREAD_COND_INITIALIZER;
void print(int val)
{
printf("获取一个新数据:%d\n",val);
}
void *thread1(void *arg)
{
srand(time(NULL));
while (1)
{
pthread_mutex_lock(&mutex);//加锁互斥量
q.push(rand()%100+1);
//向队列中插入数据
printf("插入一个新数据\n");
pthread_mutex_unlock(&mutex);//解锁互斥量
//通知线程2条件发生改变
pthread_cond_signal(&condition);
sleep(1);
}
}
void *thread2(void *arg)
{
srand(time(NULL));
while (1)
{
pthread_mutex_lock(&mutex);//加锁互斥量
//若队列为空,则休眠等待条件改变
while (q.empty())
pthread_cond_wait(&condition, &mutex);
//若队列不为空,则从队列中取出一个数据
int val=q.front();
q.pop();
pthread_mutex_unlock(&mutex);//解锁互斥量
//处理数据
print(val);
sleep(1);
}
}
int main()
{
pthread_t pit1;
//线程1标志符
pthread_t pit2;
//线程2标识符
int err=pthread_create(&pit1,NULL,thread1,NULL);//创建线程1
if(err!=0)
{
perror("creat thread1 error\n");
exit(1);
}
err=pthread_create(&pit2,
NULL, thread2,
NULL); //创建线程2
if(err!=0)
{
perror("creat thread2 error\n");
exit(1);
}
while (1)
{}
return 0;
}
2.用两个线程实现如下功能:主线程负责读取数据,当遇到特殊字符"end"后退出程序,另一个线程负责处理这些输入的数据(输出其字符串长度)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
#define WORK_SIZE 1024
//缓冲区大小
pthread_mutex_t work_mutex; //互斥量
int time_to_exit=0;
//退出标记变量
char work_area[WORK_SIZE];
//缓冲区
void *thread_function(void *arg)//线程功能函数
{
sleep(1);
pthread_mutex_lock(&work_mutex);//加锁,保证每次输入后都能进入该线程处理
while (strncmp("end",work_area,3)!=0)//判断是否结束
{
printf("You input %d characters\n",strlen(work_area)-1);//输出字符串长度
work_area[0]='\0';//相当于清空缓冲区
pthread_mutex_unlock(&work_mutex);//解锁互斥量
sleep(1);
//判断是否在主线程执行前又再次执行该线程
pthread_mutex_lock(&work_mutex);
while (work_area[0]=='\0')
{
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit=1;//更新退出标记
work_area[0]='\0';
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);//线程退出
}
int main()
{
int res;
pthread_t a_thread;
//线程标志符
void *thread_result;
res=pthread_mutex_init(&work_mutex,NULL);//初始化互斥量
if(res!=0)
{
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res=pthread_create(&a_thread,
NULL,thread_function,
NULL);
if (res!=0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);//加锁保证输出和输入的原子性
printf("Input some text,Enter 'end'to finish\n");
while (!time_to_exit)
{
fgets(work_area,WORK_SIZE,stdin);
//输入成功后即可解锁
pthread_mutex_unlock(&work_mutex);
//避免在功能线程未执行前再次调用主线程,这里需要进行处理
while (1)
{
pthread_mutex_lock(&work_mutex);
if(work_area[0]!='\0')//功能线程函数还没有处理完毕
{
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
else
break;
//处理完毕退出
}
}
pthread_mutex_unlock(&work_mutex);
printf("Waiting for thread to finish...\n");
res=pthread_join(a_thread, &thread_result);//等待功能线程退出
if(res!=0)
{
printf("Thread join failed\n");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
pthread_mutex_destroy(&work_mutex);//销毁互斥量
return 0;
}
函数说明:
[cpp]
view plaincopyprint?
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
#include <pthread.h> int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
返回值:0代表成功,错误号代表失败
参数mutex对条件句进行保护,线程2自动把加锁的互斥量传给此函数,函数把线程2放到等待条件的线程列表上,然后对互斥量进行自动解锁,这两步操作属于原子操作,这样就不会造成条件检查和线程进入休眠状态等待之间有其它线程进入的问题,当线程2因条件不满足而进入休眠后,因为互斥量已经被解锁,于是线程1就可以加锁互斥量并将收到的分组放到队列尾,然后主动解锁互斥量,接着线程1再调用下面的pthread_cond_signal函数通知线程2条件已经发生变化。
[cpp]
view plaincopyprint?
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
#include <pthread.h> int pthread_cond_signal(pthread_cond_t *cond);
返回值:0代表成功,错误号代表失败。
由于此条件发生了改变,则pthread_cond_wait函数返回,保护条件的互斥量将再次被自动加锁(注意这里是自动加锁,不需要线程2主动加锁),线程2被唤醒,于是就可以对临界资源进行操作,即线程2从队列中取出下一个分组并主动对互斥量进行解锁,之后再对该分组进行后续的处理。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <time.h>
std::queue<int>q;
//静态初始化互斥量
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//静态初始化条件变量
pthread_cond_t condition=PTHREAD_COND_INITIALIZER;
void print(int val)
{
printf("获取一个新数据:%d\n",val);
}
void *thread1(void *arg)
{
srand(time(NULL));
while (1)
{
pthread_mutex_lock(&mutex);//加锁互斥量
q.push(rand()%100+1);
//向队列中插入数据
printf("插入一个新数据\n");
pthread_mutex_unlock(&mutex);//解锁互斥量
//通知线程2条件发生改变
pthread_cond_signal(&condition);
sleep(1);
}
}
void *thread2(void *arg)
{
srand(time(NULL));
while (1)
{
pthread_mutex_lock(&mutex);//加锁互斥量
//若队列为空,则休眠等待条件改变
while (q.empty())
pthread_cond_wait(&condition, &mutex);
//若队列不为空,则从队列中取出一个数据
int val=q.front();
q.pop();
pthread_mutex_unlock(&mutex);//解锁互斥量
//处理数据
print(val);
sleep(1);
}
}
int main()
{
pthread_t pit1;
//线程1标志符
pthread_t pit2;
//线程2标识符
int err=pthread_create(&pit1,NULL,thread1,NULL);//创建线程1
if(err!=0)
{
perror("creat thread1 error\n");
exit(1);
}
err=pthread_create(&pit2,
NULL, thread2,
NULL); //创建线程2
if(err!=0)
{
perror("creat thread2 error\n");
exit(1);
}
while (1)
{}
return 0;
}
2.用两个线程实现如下功能:主线程负责读取数据,当遇到特殊字符"end"后退出程序,另一个线程负责处理这些输入的数据(输出其字符串长度)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
#define WORK_SIZE 1024
//缓冲区大小
pthread_mutex_t work_mutex; //互斥量
int time_to_exit=0;
//退出标记变量
char work_area[WORK_SIZE];
//缓冲区
void *thread_function(void *arg)//线程功能函数
{
sleep(1);
pthread_mutex_lock(&work_mutex);//加锁,保证每次输入后都能进入该线程处理
while (strncmp("end",work_area,3)!=0)//判断是否结束
{
printf("You input %d characters\n",strlen(work_area)-1);//输出字符串长度
work_area[0]='\0';//相当于清空缓冲区
pthread_mutex_unlock(&work_mutex);//解锁互斥量
sleep(1);
//判断是否在主线程执行前又再次执行该线程
pthread_mutex_lock(&work_mutex);
while (work_area[0]=='\0')
{
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit=1;//更新退出标记
work_area[0]='\0';
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);//线程退出
}
int main()
{
int res;
pthread_t a_thread;
//线程标志符
void *thread_result;
res=pthread_mutex_init(&work_mutex,NULL);//初始化互斥量
if(res!=0)
{
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res=pthread_create(&a_thread,
NULL,thread_function,
NULL);
if (res!=0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);//加锁保证输出和输入的原子性
printf("Input some text,Enter 'end'to finish\n");
while (!time_to_exit)
{
fgets(work_area,WORK_SIZE,stdin);
//输入成功后即可解锁
pthread_mutex_unlock(&work_mutex);
//避免在功能线程未执行前再次调用主线程,这里需要进行处理
while (1)
{
pthread_mutex_lock(&work_mutex);
if(work_area[0]!='\0')//功能线程函数还没有处理完毕
{
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
else
break;
//处理完毕退出
}
}
pthread_mutex_unlock(&work_mutex);
printf("Waiting for thread to finish...\n");
res=pthread_join(a_thread, &thread_result);//等待功能线程退出
if(res!=0)
{
printf("Thread join failed\n");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
pthread_mutex_destroy(&work_mutex);//销毁互斥量
return 0;
}
相关文章推荐
- 就业窍门:4. 了解企业,了解企业用人心理
- 就业窍门:5. 务实,也许就有机会
- EL表达式复习
- 将自己apk打包进其他apk安装思路
- popupMenu下拉菜单列表
- Xcode最近的那些破事
- 就业窍门:3. 无论愿不愿意,都尽量从专业考虑
- 潘鹏整理WPF(9)基于范围的控件Slider&&PrograssBar
- 最长公共子序列(LCS)
- 怎么样cocos2d-x正在使用ECS(实体-包裹-制)建筑方法来开发一款游戏?
- 最长公共子序列(LCS)
- 就业窍门:2. 不要让兴趣影响就业机会
- CART分类决策树、回归树和模型树算法详解及Python实现
- Xcode下载结果校验
- 百度、腾讯面试题
- uva 1660 & poj 1966(点连通度)
- Fiddler对安卓应用手机抓包图文教程
- JQuery 阻止事件冒泡
- Linux系统grep及正则表达式详解
- win10如何新建公文包? Win10添加Win7公文包的方法