天天看點

Linux上的線程控制,以及信号量線程控制

線程控制

  • 第一題
完成了如下功能:線程1把1,2,3,…,10列印在螢幕上(每隔4秒鐘列印一個);另一個線程2把11,12,…,20列印在螢幕上(每隔2秒鐘列印一個)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
void *thread1_proc(void *arg)
{
	int i=0;
	while(i<10)
	{
		printf("thread1:%-5d",i);
		fflush(stdout);//printf是基于行緩沖的:隻有在緩沖區滿、重新整理緩沖區或者遇到換行符的時候才把字元串顯示在螢幕上,是以手動調用fflush重新整理緩沖區
		sleep(4);
		i++;
	}
	printf("Thread1 finished!\n");
	pthread_exit(NULL);
}

void *thread2_proc(void *arg)
{
	int i=10;
	while(i<20)
	{
		printf("thread2:%-5d",i);
		fflush(stdout);
		sleep(2);
		i++;
	}
	printf("Thread2 finished!\n");
	pthread_exit(NULL);
}

void *m_thread_proc(void *arg){
	/** 
	* if flag==1
	* output 1-10 at intervals of four seconds
	* else output 11-20 at intervals of two seconds
	*/
	int flag=(int)arg;
	for(int i=flag==1?1:10;i<=10*flag;i++){
		printf("thread2:%-5d",i);
		fflush(stdout);
		sleep(2*flag);
	}
}

void *mm_thread_proc(void *arg){
	int *marg=(int*)arg;
	
	for(int i=marg[1];i<=marg[2];i++){
		printf("thread%d:%-5d",marg[0],i);
		fflush(stdout);
		sleep(marg[3]);
	}
}

int main()
{
	pthread_t thread1,thread2;
	int flag_1=1,flag_2=2;
	
	// 	thread name [0]
	// 	output [1]--[12]  
	//	delay [2] s
	int thread_1_arg[]={1,1,10,4};
	int thread_2_arg[]={2,11,20,2};
	
	/* 
	if(pthread_create(&thread1,NULL,thread1_proc,NULL)!=0)
		perror("Create thread1 failed");
	if(pthread_create(&thread2,NULL,thread2_proc,NULL)!=0)
		perror("Create thread2 failed");
	*/
		
	/* m_thread_proc
	if(pthread_create(&thread1,NULL,m_thread_proc,flag_1)!=0)
		perror("Create thread1 failed");
	if(pthread_create(&thread2,NULL,m_thread_proc,flag_2)!=0)
		perror("Create thread2 failed");
	*/
	
	if(pthread_create(&thread1,NULL,mm_thread_proc,thread_1_arg)!=0)
		perror("Create thread1 failed");
	if(pthread_create(&thread2,NULL,mm_thread_proc,thread_2_arg)!=0)
		perror("Create thread2 failed");
		
	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);
}

           
  1. 如果把參考代碼中的兩個pthread_join注釋掉後會正常工作嗎?為什麼?

不會,如果沒有pthread_join來阻塞等待子線程的話,主線程就提前結束了,沒辦法正常工作。

  1. 如果把thread2_proc函數中的pthread_exit換成exit,程式運作結果又有什麼不同?

線程二在輸出10個數之後,程式就結束了,exit函數是用來結束整個程式的,而pthread_exit是用來結束目前線程,而pthread_cancel可以用來結束其他子線程。

  1. 如果要求線程1、線程2共用同一個線程入口函數該如何修改代碼?

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-W97d62L5-1616598008382)(https://i.loli.net/2021/03/24/FsHPtSCbDRq6JX9.jpg)]

  • 第二題
(反複的過程,不能隻做一次)主線程負責從鍵盤擷取(1)兩個整數,子線程負責對這兩個整數完成求和(2)運算并把結果列印出來,請程式設計實作該功能,并嘗試是否可以要利用全局變量完成兩個線程的同步。
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
sem_t can_add;//能夠進行加法計算的信号量
sem_t can_scanf;//能夠從鍵盤輸入的信号量
int x,y;
void *thread_add(void *arg)//加法線程入口函數
{
	while(1)
	{
		sem_wait(&can_add);//申請信号量
		printf("x+y=%d\n",x+y);
		sem_post(&can_scanf);//釋放信号量
	}
}
int main()
{
	pthread_t tid;
	sem_init(&can_add,0,0);//初始化can_add信号量
	sem_init(&can_scanf,0,1);	//初始化can_scanf信号量
	if(pthread_create(&tid,NULL,thread_add,NULL)<0)
	{
		printf("Create thread_add failed!\n");
		exit(0);
	}
	while(1)
	{
		sem_wait(&can_scanf);//申請信号量
		printf("Please input two integers:");
		scanf("%d%d",&x,&y);
		sem_post(&can_add);///釋放信号量
	}		
}
           
  • 使用全局變量來進行鎖
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
 
int x,y;
int can_add,can_scanf;
void *thread_add(void *arg)//加法線程入口函數
{
	while(1)
	{
		if(can_add==1){
			can_add=0; 
			printf("x+y=%d\n",x+y);
			can_scanf=1;
		}
	}
}
int main()
{
	pthread_t tid;
	can_add=0;
	can_scanf=1;
	
	if(pthread_create(&tid,NULL,thread_add,NULL)<0)
	{
		printf("Create thread_add failed!\n");
		exit(0);
	}
	while(1)
	{
		if(can_scanf==1){
			can_scanf=0;
			printf("Please input two integers:");
			scanf("%d%d",&x,&y);
			can_add=1;
		}
		
	}		
}

           
  • 第三題

    利用信号量實作:

    主線程負責從鍵盤擷取兩個整數,子線程1負責對這兩個整數完成求和運算并把結果列印出來,子線程2負責對這兩個整數完成乘法運算并列印出來。三個線程要求遵循如下同步順序:

    (1) 主線程擷取兩個數;

    (2) 子線程1計算;

    (3) 子線程2計算;

    (4) 轉(1)

    #include <stdio.h>
    #include <semaphore.h>
    #include <pthread.h>
    #include <stdlib.h>
    sem_t can_add,can_scanf,can_mul;
    int x,y;
    void *thread_add(void *arg)//加法線程入口函數
    {
    	while(1)
    	{
    		sem_wait(&can_add);//申請加法信号量
    		printf("x+y=%d\n",x+y);
    		sem_post(&can_mul);//釋放乘法信号量
    	}
    }
    
    void *thread_mul(void *arg)//乘法法線程入口函數
    {
    	while(1)
    	{
    		sem_wait(&can_mul);//申請信号量
    		printf("x*y=%d\n",x*y);
    		sem_post(&can_scanf);//釋放信号量
    	}
    }
    
    int main()
    {
    	pthread_t tid[2];
    	sem_init(&can_add,0,0);	//初始化can_add信号量
    	sem_init(&can_scanf,0,1);	//初始化can_scanf信号量
    	sem_init(&can_mul,0,0);	//初始化can_scanf信号量
    	
    	if(pthread_create(&tid[0],NULL,thread_add,NULL)<0)
    	{
    		printf("Create thread_add failed!\n");
    		exit(0);
    	}
    	
    	if(pthread_create(&tid[1],NULL,thread_mul,NULL)<0)
    	{
    		printf("Create thread_mul failed!\n");
    		exit(0);
    	}
    	
    	while(1)
    	{
    		sem_wait(&can_scanf);//申請信号量
    		printf("Please input two integers:");
    		scanf("%d%d",&x,&y);
    		sem_post(&can_add);///釋放信号量
    	}		
    }