我有兩個我創建的程序。一個是myThreads.c,另一個是myThreads_test.c,全部在同一個目錄中。在那個目錄中,我也有libslack.c,我使用它作爲列表功能。 Finaly,我有一個myThreads.h許多無效的符號索引和未定義的主要參考
我嘗試使用編譯:
gcc -o myThreads_test.c myThreads.c -DHAVE_PTHREAD_RWLOCK=1 -lslack -lrt
或
gcc -o myThreads.c myThreads_test.c -DHAVE_PTHREAD_RWLOCK=1 -lslack -lrt
,並得到了以下錯誤:
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 20 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 21 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 22 has invalid symbol index 21
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
這是怪異因爲它似乎鏈接器拋出錯誤而不是編譯器。除此之外,根據上述編譯命令中c程序的順序,myThreads.c被刪除或myThreads_test.c被刪除。我以前見過。
所以我試着編譯上面的不同行。我有一種感覺,它與我編譯的方式有關。
這裏是myThreads.c
/*!
@file myThreads.c
An implementation of a package for creating, using and
managing preemptive threads in linux.
*/
// Assignment 1
// Author: Georges Krinker
// Student #: 260369844
// Course: ECSE 427 (OS)
// Note: This file has been commented using doxygen style.
// The API can be found at gkrinker.com/locker/OS/pa1
// Refer to doxygen.org for more info
/********************************************//**
* Includes
***********************************************/
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "myThreads.h"
/********************************************//**
* Defines
***********************************************/
#define MAX_NUMBER_OF_THREADS 20 ///< Limit on number of threads that can be created
#define MAX_NUMBER_OF_SEMAPHORES 5 ///< Limit on number of semaphores that can be created
#define DEFAULT_QUANTUM 250 ///< Default value for quantum if non is specified
/**
* Thread States
*/
#define BLOCKED 0
#define RUNNABLE 1
#define EXIT 2
#define RUNNING 3
#define NOTHREAD -1
/**
* Error Handling
*/
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)
/********************************************//**
* Global Variables
***********************************************/
static ucontext_t mainContext; ///< Main context for initial thread
static int quantum; ///< Quantum
static int threads_completed; ///< 1 if all threads finished execution, ie EXIT state
static int currentThread; ///< ID of currently running thread
static long dispatcherCount; ///< Number of times the dispatcher has been called.
static List *runQueue; ///< Thread Run Queue. Holds indices to the tcb table
static mythread_control_block table[MAX_NUMBER_OF_THREADS]; ///< Holds thread control blocks
static semaphore semaphores[MAX_NUMBER_OF_SEMAPHORES]; ///< Holds semaphores
static int tableIndex; ///< Holds the next free table index in the table
static int semaphoresIndex; ///< Holds the enxt free semaphore index in the table
static sigset_t block_alarm; ///< The signal set that will be blocked
/********************************************//**
* Functions
***********************************************/
/**
* This function initializes all the global data structures for the thread system.
*
* Creates a new Run Queue and initilaizes the indices for both the
* TCB table and Semaphore table to 0. It then initializes the TCB
* and semaphore table. Finally, [TO BE COMPLETED]
*/
int mythread_init(){
runQueue = list_create(NULL);
tableIndex=0;
semaphoresIndex=0;
currentThread = -1; //No threads have been created yet.
int i;
quantum = DEFAULT_QUANTUM;
threads_completed = 0;
//Set all Thread Statuses to 'No Thread' in the TCB table
for(i=0;i<MAX_NUMBER_OF_THREADS;i++){
table[i].status=NOTHREAD;
}
// Set all semaphores to inactive
int j;
for(j=0; j<MAX_NUMBER_OF_SEMAPHORES; j++)
semaphores[j].active = 0;
sigemptyset (&block_alarm);
sigaddset (&block_alarm, SIGALRM);
}
/**
* This function creates a new thread.
*
* The function is responsible for allocating the stack and setting
* up the user context appropriately. The newly created thread
* starts running the threadfunc function when it starts. The
* threadname is stored in the TCB and is printed for info
* purposes The newly created thread is in the RUNNABLE
* state when inserted into the system. It is added to the run queue.
* @return the ID of the newly created thread
* @param *threadfunc() function to be called on context switch
* @param stacksize size of stack to be allocated to
*/
int mythread_create(char *threadName, void (*threadfunc)(), int stacksize){
// Handle the error if any
if (getcontext(&table[tableIndex].context) == -1)
handle_error("ERROR IN GETCONTEXT!");
// Allocate a stack for the new thread and set it's return context
table[tableIndex].context.uc_stack.ss_size = stacksize; //Set stack size
table[tableIndex].context.uc_stack.ss_sp = malloc(stacksize); // allocate that space
table[tableIndex].context.uc_link = &mainContext; // set the return context as the main Context
// Modify the context and fill out the thread info on the TCB table
makecontext(&table[tableIndex].context, threadfunc, 0); // set the function call and 0 arguments
table[tableIndex].name = threadName; // set the thread name
table[tableIndex].threadID = tableIndex; // set the thread ID
table[tableIndex].status = RUNNABLE; // set the thread as RUNNABLE
runQueue = list_append_int(runQueue, tableIndex); // add it to the run queue
tableIndex++; //point to the next free slot
return tableIndex-1; // returns ID of thread
}
/**
* This function is called at the end of the function that was invoked
* by the thread.
*
* The function firstly masks signals, sets the status of that
* thread to 'EXIT' and then unblocks signals before returning.
*/
void mythread_exit(){
sigprocmask (SIG_BLOCK, &block_alarm, NULL);
table[currentThread].status=EXIT;
sigprocmask (SIG_UNBLOCK, &block_alarm, NULL);
}
/**
* Sets the quantum for the round robin (RR) scheduler.
*
* @param quantum_size quantum size in us
*/
void set_quantum_size(int quantum_size){
quantum = quantum_size;
}
/**
* Schedules threads in a Round Robin fashion.
*
* The function starts by checking if there are no more threads to run.
* If that is the case, it sets threads_completed to 1 so that
* run_threads() will terminate and resume to the mainContext.
* If there are still runnable threads, the dispatcher switches threads
* by swapping context, and putting the expired thread at the end of the
* run queue. Finally, if there is only one runnable thread, that thread
* is allowed to run for one more quantum.
*/
void dispatcher(){
dispatcherCount++;
//if there are no more threads to run, and the current thread is done, set
// threads_completed to 1
if(list_empty(runQueue) && table[currentThread].status==EXIT){
threads_completed=1;
swapcontext(&table[currentThread].context, &mainContext);
}
//else switch to the next thread
else if(!list_empty(runQueue)){
int nextThread = list_shift_int(runQueue);
int tempCurrent = currentThread;
currentThread = nextThread;
// if the current thread (which is yielding to the next runnable thread) is runnable, queue it
//back in the runqueue
if(table[tempCurrent].status != EXIT && table[tempCurrent].status!=BLOCKED){
runQueue = list_append_int(runQueue, tempCurrent);
table[tempCurrent].status = RUNNABLE;
}
table[nextThread].status = RUNNING; //set the the enxt thread to run
sigprocmask (SIG_BLOCK, &block_alarm, NULL); //stop the dispatcher from being called while updating timing
clock_gettime(CLOCK_REALTIME, &table[tempCurrent].stopTime); //record stop time
table[tempCurrent].elapsedTime += (double) (table[tempCurrent].stopTime.tv_nsec - table[tempCurrent].startTime.tv_nsec); //update elapsed time
clock_gettime(CLOCK_REALTIME, &table[currentThread].startTime);//record start timer of new thread
sigprocmask (SIG_UNBLOCK, &block_alarm, NULL);
//switch context
swapcontext(&table[tempCurrent].context, &table[nextThread].context);
}
else{
//Keep the only thread that's runnable for 1 more quantum (do nothing!)
}
}
/**
* The runthreads() switches control from the main thread to one of the threads in the runqueue.
*
* The function starts by defining a signal timer that triggers every
* quantum usecs and calls the dispatcher. The function then starts the
* first thread by doing a context switch.
*/
void runthreads(){
//Set up the signal alarm to call dispatcher() every quantum interval
struct itimerval tval;
sigset(SIGALRM, dispatcher);
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_usec = quantum;
tval.it_value.tv_sec = 0;
tval.it_value.tv_usec = quantum;
setitimer(ITIMER_REAL, &tval, 0);
// If there is nothing to run, throw an error!
if(list_empty(runQueue)){
handle_error("In runthreads: RUN QUEUE IS EMPTY!");
}
else{
int nextThread = list_shift_int(runQueue); //find the next thread to run
currentThread = nextThread; //make it the current thread
table[currentThread].status = RUNNING; //set it to running
sigprocmask (SIG_BLOCK, &block_alarm, NULL); //stop signal from interrupting the timing calculations
clock_gettime(CLOCK_REALTIME, &table[currentThread].startTime); //record start time of the new current thread
sigprocmask (SIG_UNBLOCK, &block_alarm, NULL);
swapcontext(&mainContext, &table[nextThread].context); //swap context
}
//only stop when there are no more threads to run!
while(!threads_completed);
}
/**
* This function creates a semaphore and sets its initial value to the given parameter.
*
* @param value initial semaphore value
*/
int create_semaphore(int value){
// handle error as usual if value is less than 0
if(value < 0)
handle_error("semaphore initialization failed - value less than 0.");
else{
semaphores[semaphoresIndex].initialValue = value; //set initial value to value
semaphores[semaphoresIndex].value = semaphores[semaphoresIndex].initialValue; //set value
semaphores[semaphoresIndex].active = 1; // make it ative now
semaphores[semaphoresIndex].waitingThreads = list_create(NULL); //create a waitingThreads list for it
}
semaphoresIndex++;
return semaphoresIndex-1; //return ID
}
/**
* Calls wait() on a Semaphore
*
* When a thread calls this function, the value of the semaphore is decremented.
* If the value goes below 0, the thread is put into a WAIT state. That means
* calling thread is taken out of the runqueue if the value of the semaphore
* goes below 0.
* @param semaphore index of semaphore to be manipulated in the table
*
*/
void semaphore_wait(int semaphore){
long oldDispatcherCount=dispatcherCount;
//if trying to access a semaphore that doesn't show or is inactive handle it
if(semaphore > semaphoresIndex || semaphores[semaphore].active==0)
handle_error("Wrong semaphore index in wait()");
sigprocmask (SIG_BLOCK, &block_alarm, NULL); //mask signals for changing semaphore value (indivisibility)
if(--semaphores[semaphore].value<0){ // if value < 0, add thread to waiting queue
list_append_int(semaphores[semaphore].waitingThreads, currentThread);
table[currentThread].status = BLOCKED; // change the status of the semaphore to BLOCKED
}
sigprocmask (SIG_UNBLOCK, &block_alarm, NULL); // Re-nable signals
while(dispatcherCount == oldDispatcherCount); //wait for the scheduler to switch threads (could be made more efficient)
}
/**
* Calls signal() on a Semaphore
*
* When a thread calls this function the value of the semaphore is incremented.
* If the value is not greater than 0, then we should at least have one thread
* waiting on it. The thread at the top of the wait queue associated with the
* semaphore is dequeued from the wait queue and queued in the run queue. The
* thread state is then set to RUNNABLE.
* @param semaphore index of semaphore to be manipulated in the table
*
*/
void semaphore_signal(int semaphore){
//if trying to access a semaphore that doesn't show or is inactive handle it
if(semaphore > semaphoresIndex || semaphores[semaphore].active <0)
handle_error("Wrong semaphore index in signal()");
if(++semaphores[semaphore].value<=0){ // if there are threads waiting...
if(list_empty(semaphores[semaphore].waitingThreads)) //contradiction! No thread waiting? Error!
handle_error("in Semaphore signal: there should be at least one waiting thread in semaphore");
//Dequeue a waiting thread and set it to RUNNABLE. Then add it to the run queue
int readyThread = list_shift_int(semaphores[semaphore].waitingThreads);
table[readyThread].status = RUNNABLE;
list_append_int(runQueue, readyThread);
}
}
/**
* Destroys a semaphore.
*
* A call to this function while threads are waiting on the semaphore should fail.
* That is the removal process should fail with an appropriate error message.
* If there are no threads waiting, this function will proceed with the removal
* after checking whether the current value is the same as the initial value of
* the semaphore. If the values are different, then a warning message is
* printed before the semaphore is destroyed.
* @param semaphore index of semaphore to be manipulated in the table
*
*/
void destroy_semaphore(int semaphore){
//if trying to access a semaphore that doesn't show or is inactive handle it
if(semaphore > semaphoresIndex || semaphores[semaphore].active ==0)
handle_error("Wrong semaphore index in destroy()");
//initil and final value check
if(semaphores[semaphore].value != semaphores[semaphore].initialValue){
puts("\nWARNING: Destroying a semaphore with different initial and final values!\n");
}
//check that there are no threads waiting on this baby
if(!list_empty(semaphores[semaphore].waitingThreads)){
printf("Semaphore %i was not destroyed since one or more threads are waiting on it..\n",semaphore);
}
//destroy it by setting it to inactive!
else{
semaphores[semaphore].active = 0;
}
}
/**
* Prints the state of all threads that are maintained by the library at
* any given time.
*
* For each thread, it prints the following information in a tabular
* form: thread name, thread state (print as a string RUNNING, BLOCKED,
* EXIT, etc), and amount of time run on CPU.
*
*/
void my_threads_state(){
int i;
char* string;
for(i=0; i<MAX_NUMBER_OF_THREADS; i++){
if(table[i].status != -1){
switch(table[i].status){
case 0: string = "BLOCKED"; break;
case 1: string = "RUNNABLE"; break;
case 3: string = "RUNNING"; break;
case 2: string = "EXIT"; break;
}
printf("thread name: %s with ID number: %i is in state: %s and has run for %fms.\n",
table[i].name, i, string, table[i].elapsedTime/1000000);
}
}
}
這裏是myThreads.h
/*!
@file myThreads.h
An implementation of a package for creating, using and
managing preemptive threads in linux.
*/
// Multiple-include guard
#ifndef __myThreads_H_
#define __myThreads_H_
#include <ucontext.h>
#include <slack/std.h>
#include <slack/list.h>
/********************************************//**
* Structures
***********************************************/
/*! \brief Structure that represents the thread control block (TCB).
*/
typedef struct _mythread_control_block {
ucontext_t context;
char *name;
int threadID; //Between 0-# of Threads
int status; // Any of the above defines
struct timespec startTime; //when it was created
struct timespec stopTime; // when it was stopped
double elapsedTime; //start-stop in ns
}mythread_control_block;
typedef struct _mythread_semaphore{
int value;
int initialValue;
int active;
List *waitingThreads; // holds indices to the semaphores table
}semaphore;
/********************************************//**
* Functions
***********************************************/
/**
* This function initializes all the global data structures for the thread system.
*
* Creates a new Run Queue and initilaizes the indices for both the
* TCB table and Semaphore table to 0. It then initializes the TCB
* and semaphore table. Finally, [TO BE COMPLETED]
*/
int init_my_threads();
/**
* This function creates a new thread.
*
* The function is responsible for allocating the stack and setting
* up the user context appropriately. The newly created thread
* starts running the threadfunc function when it starts. The
* threadname is stored in the TCB and is printed for info
* purposes The newly created thread is in the RUNNABLE
* state when inserted into the system. It is added to the run queue.
* @return the ID of the newly created thread
* @param *threadfunc() function to be called on context switch
* @param stacksize size of stack to be allocated to
*/
int mythread_create(char *threadName, void (*threadfunc)(), int stacksize);
/**
* This function is called at the end of the function that was invoked
* by the thread.
*
* The function firstly masks signals, sets the status of that
* thread to 'EXIT' and then unblocks signals before returning.
*/
void mythread_exit();
/**
* Sets the quantum for the round robin (RR) scheduler.
*
* @param quantum_size quantum size in us
*/
void set_quantum_size(int quantum_size);
/**
* Schedules threads in a Round Robin fashion.
*
* The function starts by checking if there are no more threads to run.
* If that is the case, it sets threads_completed to 1 so that
* run_threads() will terminate and resume to the mainContext.
* If there are still runnable threads, the dispatcher switches threads
* by swapping context, and putting the expired thread at the end of the
* run queue. Finally, if there is only one runnable thread, that thread
* is allowed to run for one more quantum.
*/
void dispatcher();
/**
* The runthreads() switches control from the main thread to one of the threads in the runqueue.
*
* The function starts by defining a signal timer that triggers every
* quantum usecs and calls the dispatcher. The function then starts the
* first thread by doing a context switch.
*/
void runthreads();
/**
* This function creates a semaphore and sets its initial value to the given parameter.
*
* @param value initial semaphore value
*/
int create_semaphore(int value);
/**
* Calls wait() on a Semaphore
*
* When a thread calls this function, the value of the semaphore is decremented.
* If the value goes below 0, the thread is put into a WAIT state. That means
* calling thread is taken out of the runqueue if the value of the semaphore
* goes below 0.
* @param semaphore index of semaphore to be manipulated in the table
*
*/
void semaphore_wait(int semaphore);
/**
* Calls signal() on a Semaphore
*
* When a thread calls this function the value of the semaphore is incremented.
* If the value is not greater than 0, then we should at least have one thread
* waiting on it. The thread at the top of the wait queue associated with the
* semaphore is dequeued from the wait queue and queued in the run queue. The
* thread state is then set to RUNNABLE.
* @param semaphore index of semaphore to be manipulated in the table
*
*/
void semaphore_signal(int semaphore);
/**
* Prints the state of all threads that are maintained by the library at
* any given time.
*
* For each thread, it prints the following information in a tabular
* form: thread name, thread state (print as a string RUNNING, BLOCKED,
* EXIT, etc), and amount of time run on CPU.
*
*/
void my_threads_state();
#endif
最後,這裏是myThreads_test.c
/*!
@file myThreads_test.c
A test program for testing myThreads.c
*/
// Assignment 1
// Author: Georges Krinker
// Student #: 260369844
// Course: ECSE 427 (OS)
// Note: This file has been commented using doxygen style.
// The API can be found at gkrinker.com/locker/OS/pa1
// Refer to doxygen.org for more info
/********************************************//**
* Includes
***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include "myThreads.h"
/********************************************//**
* Global Variables
***********************************************/
int mutex; //Mutex used by shared resources
int a;
int b;
int mult;
void multiply() {
int i;
for(i=0;i<1000;++i){
semaphore_wait(mutex);
mult=mult+(a*b);
a++;
b++;
semaphore_signal(mutex);
}
mythread_exit();
}
int main(){
a=0;
b=0;
mult=0;
mutex=create_semaphore(1);
int threads = 12; // How many threads are to be created
char* names[] = {
"thread 0",
"thread 1",
"thread 2",
"thread 3",
"thread 4",
"thread 5",
"thread 6",
"thread 7",
"thread 8",
"thread 9",
"thread 10",
"thread 11"
};
mythread_init(); // Initialize Package
set_quantum_size(50); // set quantum to 50
//Create threads
int i=0;
int dummy = 0;
for(i=0; i<threads; i++)
{
dummy=mythread_create(names[i], (void *) &multiply, 100);
}
runthreads(); // Run threads
my_threads_state(); // See state
printf("The value of mult is %d\n", mult);
return 0;
}