题目一:子线程循环5次,接着主线程循环10次,
接着又回到子线程循环5次,接着再回到主线程又循环10次,
如此循环6次,试写出代码。
解法一,mutex
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>
//如果只有一个mutex,在创建了子线程,主线程休眠后,让子线程执行,子线程执行了10次后,休眠。
//过了这个休眠时间,调度线程执行的时候,如果系统任务多,可能仍是子线程在执行的。
pthread_mutex_t mutex;
//临界区数据
//00表示初始状态
//01表示之前在执行子线程
//10表示之前在执行主线程
int flag1,flag2;
//如果不用条件变量,只用mutex。
//那么子线程和主线程都会不断的获得mutex,然后判断自己是否该执行,如果不该执行,就释放,然后sleep下。
//如果可以执行就执行,然后再sleep。
//这样效率太低。
//pthread_cond_t cond;
void loopChild(){
printf("child: ");
for(int i = 1; i <= 5; i++)
printf("%d ", i);
printf("\n");
}
void loopParent(){
printf("Parent: ");
for(int i = 1; i <= 10; i++ )
printf("%d ", i);
printf("\n");
}
void setParentFlag(){
flag1 = 1;
flag2 = 0;
}
void setChildFlag(){
flag1 = 0;
flag2 = 1;
}
//轮到子线程执行
bool isChildTurn(){
if( 1 == flag1 && 0 == flag2)
return true;
return false;
}
//轮到父线程执行
bool isParentTurn(){
if( 0 == flag1 && 1 == flag2)
return true;
return false;
}
void *func(void *arg) {
while(1){
pthread_mutex_lock(&mutex);
if( isChildTurn()){
//之前在执行主线程
setChildFlag();
loopChild();
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main() {
pthread_mutex_init(&mutex, NULL);
setParentFlag();
pthread_t pid = pthread_create(&pid, NULL, func, NULL );
sleep(1);
int cnt = 0;
while(1) {
pthread_mutex_lock(&mutex);
if( isParentTurn() ){
//之前在执行子线程
setParentFlag();
loopParent();
cnt++;
if(6 == cnt){
break;
}
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
pthread_cancel(pid);
pthread_mutex_destroy(&mutex);
exit(0);
}
解法二,使用condition variable
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>
//如果只有一个mutex,在创建了子线程,主线程休眠后,让子线程执行,子线程执行了10次后,休眠。
//过了这个休眠时间,调度线程执行的时候,如果系统任务多,可能仍是子线程在执行的。
pthread_mutex_t mutex;
//临界区数据
//00表示初始状态
//01表示之前在执行子线程
//10表示之前在执行主线程
int flag1,flag2;
//如果不用条件变量,只用mutex。
//那么子线程和主线程都会不断的获得mutex,然后判断自己是否该执行,如果不该执行,就释放,然后sleep下。
//如果可以执行就执行,然后再sleep。
//这样效率太低。
pthread_cond_t cond;
void loopChild(){
printf("child: ");
for(int i = 1; i <= 5; i++)
printf("%d ", i);
printf("\n");
}
void loopParent(){
printf("Parent: ");
for(int i = 1; i <= 10; i++ )
printf("%d ", i);
printf("\n");
}
void setParentFlag(){
flag1 = 1;
flag2 = 0;
}
void setChildFlag(){
flag1 = 0;
flag2 = 1;
}
//轮到子线程执行
bool isChildTurn(){
if( 1 == flag1 && 0 == flag2 )
return true;
return false;
}
void *func(void *arg) {
while( 1) {
pthread_mutex_lock(&mutex);
if(!isChildTurn()){
pthread_cond_wait(&cond, &mutex);
}
loopChild();
setChildFlag();
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
setParentFlag();
pthread_t pid = pthread_create(&pid, NULL, func, NULL );
sleep(1);
int cnt = 0;
while(1) {
pthread_mutex_lock(&mutex);
if(isChildTurn()){
pthread_cond_wait(&cond, &mutex);
}
loopParent();
setParentFlag();
cnt++;
if(6 == cnt){
break;
}
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
pthread_cancel(pid);
sleep(1);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
exit(0);
}
第二题
/*
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,
每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
pthread_t pidA, pidB, pidC;
sem_t semA, semB, semC;
void *funcA(void *arg) {
for(int i = 0; i < 10; i++){
sem_wait(&semA);
printf("A");
fflush(stdout);
sem_post(&semB);
}
return NULL;
}
void *funcB(void *arg) {
for(int i = 0; i < 10; i++){
sem_wait(&semB);
printf("B", i);
fflush(stdout);
sem_post(&semC);
}
return NULL;
}
void *funcC(void *arg) {
for(int i = 0; i < 10; i++){
sem_wait(&semC);
printf("C");
fflush(stdout);
sem_post(&semA);
}
return NULL;
}
int main( ) {
sem_init(&semA, 0, 1);
sem_init(&semB, 0, 0);
sem_init(&semC, 0, 0);
pthread_create(&pidA, NULL, funcA, NULL );
pthread_create(&pidB, NULL, funcB, NULL );
pthread_create(&pidC, NULL, funcC, NULL );
pthread_join(pidA, NULL);
pthread_join(pidB, NULL);
pthread_join(pidC, NULL);
sem_destroy(&semA);
sem_destroy(&semB);
sem_destroy(&semC);
exit(0);
}
第三题:生产者消费者问题
这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
解法一,使用mutex
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define NUMS 10 //表示生产,消费的次数
#define CAPACITY 5 //定义缓冲区最大值
int capacity = 0; //当前缓冲区的产品个数
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量
void* produce(void *args)
{
int i = 0;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylock);//加锁
if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区。
{
printf("Producer : buffer full, can't add item \n");
} else {//将产品放入缓冲区
++capacity;
printf("Producer : add a item, buff size is :%d\n", capacity);
i++;
}
pthread_mutex_unlock(&mylock);
}
return ((void *) 0);
}
void* consume(void *args)
{
int i = 0;
for (; i < NUMS; )
{
pthread_mutex_lock(&mylock);
if (capacity > 0)
{
--capacity;
printf("Consumer: consume an item, buff size is :%d\n", capacity);
i++;
} else {
printf("Consumer : buff is empty, can't consume item\n");
}
pthread_mutex_unlock(&mylock);
}
return ((void *) 0);
}
int main(int argc, char** argv) {
int err;
pthread_t produce_tid, consume_tid;
void *ret;
err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程
if (err != 0)
{
printf("thread creat failed :%s\n", strerror(err));
exit(-1);
}
err = pthread_create(&consume_tid, NULL, consume, NULL);
if (err != 0)
{
printf("thread creat failed :%s\n", strerror(err));
exit(-1);
}
err = pthread_join(produce_tid, &ret);//主线程等到子线程退出
if (err != 0)
{
printf("producer thread join failed :%s\n", strerror(err));
exit(-1);
}
err = pthread_join(consume_tid, &ret);
if (err != 0)
{
printf("consumer thread join failed :%s\n", strerror(err));
exit(-1);
}
return (EXIT_SUCCESS);
}
结果满足题意。但是这存在一个问题,极端情况下,生产者每次都加锁成功,那缓冲区会满,产品无法放入缓冲区。消费者会被饿死,因为他一直无法获得互斥量。
改进?
(Google面试题)
有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:
A:1 2 3 4 1 2....
B:2 3 4 1 2 3....
C:3 4 1 2 3 4....
D:4 1 2 3 4 1....
请设计程序。