20145235《信息安全系统设计基础》第13周学习总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20145235《信息安全系统设计基础》第13周学习总结相关的知识,希望对你有一定的参考价值。
过程抽象
接口
实现
函数签名
万能函数
多线程
单线程
当运行老师给的代码hello_single.c的时候,发现和老师的运行结果不一样,也没有感受到函数级并发,然而当我把这个代码删除之后,就明白了函数级并发了,没删之前运行结果为:每个一秒打出一个字符串,共进行10秒;删除之后:前4秒什么都没有输出字符串,最后1秒一下子打出了5个hello。之后5秒每隔一秒就打印出一个world。这个时候我就明白什么函数级并发了,第一次调用函数时,5个hello每隔1秒进入缓冲区,当程序调用结束后一下子打印出来,第二次调用时,因为有换行符,每隔一秒就打印出一个world。
多线程
多线程-终止
多线程-互斥
多线程-同步
线程与进程
代码运行:
condvar.c
#include <stdlib.h> #include <pthread.h> #include <stdlib.h> typedef struct _msg{ struct _msg * next; int num; } msg; msg *head; pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void *consumer ( void * p ) { msg * mp; for( ;; ) { pthread_mutex_lock( &lock ); while ( head == NULL ) pthread_cond_wait( &has_product, &lock ); mp = head; head = mp->next; pthread_mutex_unlock ( &lock ); printf( "Consume %d tid: %d\\n", mp->num, pthread_self()); free( mp ); sleep( rand() % 5 ); } } void *producer ( void * p ) { msg * mp; for ( ;; ) { mp = malloc( sizeof(msg) ); pthread_mutex_lock( &lock ); mp->next = head; mp->num = rand() % 1000; head = mp; printf( "Produce %d tid: %d\\n", mp->num, pthread_self()); pthread_mutex_unlock( &lock ); pthread_cond_signal( &has_product ); sleep ( rand() % 5); } } int main(int argc, char *argv[] ) { pthread_t pid1, cid1; pthread_t pid2, cid2; srand(time(NULL)); pthread_create( &pid1, NULL, producer, NULL); pthread_create( &pid2, NULL, producer, NULL); pthread_create( &cid1, NULL, consumer, NULL); pthread_create( &cid2, NULL, consumer, NULL); pthread_join( pid1, NULL ); pthread_join( pid2, NULL ); pthread_join( cid1, NULL ); pthread_join( cid2, NULL ); return 0; }
- 在pthread库中通过条件变量(Condition Variable)来阻塞等待一个条件,或者唤醒等待这个条件的线程。
- 线程间同步的一种情况:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。
- 从代码中可以看到,mutex用于保护资源,wait函数用于等待信号,signal函数用于通知信号。其中wait函数中有一次对mutex的释放和重新获取操作,因此生产者和消费者并不会出现死锁。
count.c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #define NLOOP 5000 int counter; void *doit( void * ); int main(int argc, char **argv) { pthread_t tidA, tidB; pthread_create( &tidA ,NULL, &doit, NULL ); pthread_create( &tidB ,NULL, &doit, NULL ); pthread_join( tidA, NULL ); pthread_join( tidB, NULL ); return 0; } void * doit( void * vptr) { int i, val; for ( i=0; i<NLOOP; i++ ) { val = counter++; printf("%x: %d \\n", (unsigned int) pthread_self(), val + 1); counter = val + 1; } }
因为资源是共享的,所以访问资源会发生冲突,导致输出值是5001,不是10000。所以代码应该引入互斥锁。获得锁的线程可以完成”读-修改-写”的操作,然后释放锁给其它线程,没有获得锁的线程只能等待而不能访问共享资源。
countwithmutex.c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #define NLOOP 5000 int counter; pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; void *doit( void * ); int main(int argc, char **argv) { pthread_t tidA, tidB; pthread_create( &tidA ,NULL, &doit, NULL ); pthread_create( &tidB ,NULL, &doit, NULL ); pthread_join( tidA, NULL ); pthread_join( tidB, NULL ); return 0; } void * doit( void * vptr) { int i, val; for ( i=0; i<NLOOP; i++ ) { pthread_mutex_lock( &counter_mutex ); val = counter++; printf("%x: %d \\n", (unsigned int) pthread_self(), val + 1); counter = val + 1; pthread_mutex_unlock( &counter_mutex ); } return NULL; }
加了互斥锁,结果便为10000.。所以在今后的多线程编程中,如果牵扯到两个线程同时访问共享资源时,必须要引入互斥锁。
createthread.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> pthread_t ntid; void printids( const char *s ) { pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); printf("%s pid %u tid %u (0x%x) \\n", s , ( unsigned int ) pid, ( unsigned int ) tid, (unsigned int ) tid); } void *thr_fn( void * arg ) { printids( arg ); return NULL; } int main( void ) { int err; err = pthread_create( &ntid, NULL, thr_fn, "new thread: " ); if ( err != 0 ){ fprintf( stderr, "can‘t create thread: %s\\n", strerror( err ) ); exit( 1 ); } printids( "main threads: " ); sleep(1); return 0; }
程序打印出了进程ID和线程的ID。
semphore.c
#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <semaphore.h> #define NUM 5 int queue[NUM]; sem_t blank_number, product_number; void *producer ( void * arg ) { static int p = 0; for ( ;; ) { sem_wait( &blank_number ); queue[p] = rand() % 1000; printf("Product %d \\n", queue[p]); p = (p+1) % NUM; sleep ( rand() % 5); sem_post( &product_number ); } } void *consumer ( void * arg ) { static int c = 0; for( ;; ) { sem_wait( &product_number ); printf("Consume %d\\n", queue[c]); c = (c+1) % NUM; sleep( rand() % 5 ); sem_post( &blank_number ); } } int main(int argc, char *argv[] ) { pthread_t pid, cid; sem_init( &blank_number, 0, NUM ); sem_init( &product_number, 0, 0); pthread_create( &pid, NULL, producer, NULL); pthread_create( &cid, NULL, consumer, NULL); pthread_join( pid, NULL ); pthread_join( cid, NULL ); sem_destroy( &blank_number ); sem_destroy( &product_number ); return 0; }
- semaphore表示信号量,semaphore变量的类型为sem_t,sem_init()初始化一个semaphore变量,value参数表示可用资源 的数量,pshared参数为0表示信号量用于同一进程的线程间同步。在用完semaphore变量之后应该调用sem_destroy()释放与semaphore相关的资源。调用sem_wait()可以获得资源,使semaphore的值减1,如果调用sem_wait()时semaphore的值已 经是0,则挂起等待。如果不希望挂起等待,可以调用sem_trywait()。调用sem_post()可以释放资 源,使semaphore的值加1,同时唤醒挂起等待的线程。
share.c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> char buf[BUFSIZ]; void *thr_fn1( void *arg ) { printf("thread 1 returning %d\\n", getpid()); printf("pwd:%s\\n", getcwd(buf, BUFSIZ)); *(int *)arg = 11; return (void *) 1; } void *thr_fn2( void *arg ) { printf("thread 2 returning %d\\n", getpid()); printf("pwd:%s\\n", getcwd(buf, BUFSIZ)); pthread_exit( (void *) 2 ); } void *thr_fn3( void *arg ) { while( 1 ){ printf("thread 3 writing %d\\n", getpid()); printf("pwd:%s\\n", getcwd(buf, BUFSIZ)); sleep( 1 ); } } int n = 0; int main( void ) { pthread_t tid; void *tret; pthread_create( &tid, NULL, thr_fn1, &n); pthread_join( tid, &tret ); printf("n= %d\\n", n ); printf("thread 1 exit code %d\\n", (int) tret ); pthread_create( &tid, NULL, thr_fn2, NULL); pthread_join( tid, &tret ); printf("thread 2 exit code %d\\n", (int) tret ); pthread_create( &tid, NULL, thr_fn3, NULL); sleep( 3 ); pthread_cancel(tid); pthread_join( tid, &tret ); printf("thread 3 exit code %d\\n", (int) tret ); }
代码主要是为了获得线程的终止状态,thr_fn 1,thr_fn 2和thr_fn 3三个函数对应终止线程的三种方法,即从线程函数return,调用pthread_exit终止自己和调用pthread_cancel终止同一进程中的另一个线程。
以上是关于20145235《信息安全系统设计基础》第13周学习总结的主要内容,如果未能解决你的问题,请参考以下文章
20145235 《信息安全系统设计基础》第05周学习总结——2