So i have this code of a node in an kinda of a data structure and the node has a read write lock
to initialize the lock i used pthread_rwlock_init before using pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
the thing is for some reason it gives an error saying that it was expected an expression before the PTHREAD_RWLOCK_INITIALIZER and i dont understand what it is because i know im not missing any ;
Code:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "state.h"
#include <pthread.h>
typedef struct inode_t {
type nodeType;
union Data data;
// ******************NEW ATTRIBUTE THAT INLCUDES THE LOCK *******************************
pthread_rwlock_t lock;
} inode_t;
void inode_table_init() {
for (int i = 0; i < INODE_TABLE_SIZE; i++) {
inode_table[i].nodeType = T_NONE;
inode_table[i].data.dirEntries = NULL;
inode_table[i].data.fileContents = NULL;
// ****************** NEW *******************************
// Initializes the lock
pthread_rwlock_init(&inode_table[i].lock ,NULL);
inode_table[i].lock = PTHREAD_RWLOCK_INITIALIZER;
}
}
int inode_create(type nType) {
/* Used for testing synchronization speedup */
insert_delay(DELAY);
for (int inumber = 0; inumber < INODE_TABLE_SIZE; inumber++) {
if (inode_table[inumber].nodeType == T_NONE) {
inode_table[inumber].nodeType = nType;
pthread_rwlock_init(&inode_table[inumber].lock ,NULL);
inode_table[inumber].lock = PTHREAD_RWLOCK_INITIALIZER;
if (nType == T_DIRECTORY) {
/* Initializes entry table */
inode_table[inumber].data.dirEntries = malloc(sizeof(DirEntry) * MAX_DIR_ENTRIES);
for (int i = 0; i < MAX_DIR_ENTRIES; i++) {
inode_table[inumber].data.dirEntries[i].inumber = FREE_INODE;
}
}
else {
inode_table[inumber].data.fileContents = NULL;
}
return inumber;
}
}
return FAIL;
}
Well it doesnt matter what the function does what it matters is that im having a strange error in the lines that im initializing the locks
Error:
fs/state.c: In function ‘inode_table_init’:
fs/state.c:34:31: error: expected expression before ‘{’ token
inode_table[i].lock = PTHREAD_RWLOCK_INITIALIZER;
^
fs/state.c: In function ‘inode_create’:
fs/state.c:81:41: error: expected expression before ‘{’ token
inode_table[inumber].lock = PTHREAD_RWLOCK_INITIALIZER;
Well any help would be appreciated.
You don't need those assignments. From the POSIX spec:
In cases where default read-write lock attributes are appropriate, the macro PTHREAD_RWLOCK_INITIALIZER can be used to initialise read-write locks that are statically allocated. The effect is equivalent to dynamic initialisation by a call to pthread_rwlock_init() with the parameter attr specified as NULL, except that no error checks are performed.
You can only use it in a variable initialization, not an assignment. And since it's equivalent to the calls on the lines before, it's redundant even it worked.
Related
Im trying to write a function that unlocks all pthread mutexes provided in an array of mutexes.
The array is mutexv and the number of mutexes in given by mutexc.
The function should return 0 on success,
-1 otherwise.
my function so far:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <alloca.h>
#include "pthread.h"
#include "multi_mutex.h"
int multi_mutex_unlock(pthread_mutex_t **mutexv, int mutexc)
{
(void) mutexv;
(void) mutexc;
pthread_mutex_init(*mutexv, NULL);
for (int i=0; i<mutexc; i++){
if (pthread_mutex_unlock(*mutexv) !=0){
return -1;
}
}
return 0;
}
having a hard time figuring out what im doing wrong.
// correct type for specifying array sizes is size_t, not int:
int multi_mutex_unlock(pthread_mutex_t **mutexv, size_t mutexc)
{
// you wouldn't initialize here, that needs to occur much earlier
//pthread_mutex_init(*mutexv, NULL);
for (size_t i = 0; i < mutexc; i++)
{
if (pthread_mutex_unlock(mutexv[i]) != 0)
// you need to index properly ^^^
{
return -1;
}
}
return 0;
}
Actually a while loop can be more elegant:
int multi_mutex_unlock(pthread_mutex_t **mutexv, size_t mutexc)
{
while(mutexc)
{
if (pthread_mutex_unlock(*mutexv) != 0)
{
return -1;
}
mutexc--; // decrement the remaining number
mutexv++; // increment the pointer to point to next mutex
}
return 0;
// or totally compact as:
for(; mutexc; --mutexc, ++mutexv)
{
if (pthread_mutex_unlock(*mutexv) != 0)
{
return -1;
}
}
}
Finally: You don't give any information on how many mutexes actually could be unlocked (or alternatively, how many have not) – you might return that number instead of -1, then any value different from originally passed mutexc would mean an error occurred.
I'm trying to make a game that requires dynamically sized arrays in C but my code isn't working even though identical code works in another one of my programs.
Here are my #includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SwinGame.h" //API for graphics, physics etc
#include <math.h>
Here are my typedefs for the relevant structs used:
typedef struct position_data
{
double x;
double y;
} position_data;
typedef enum enemy_type_data {CIRCLE, TRIANGLE, SQUARE} enemy_type_data;
typedef struct enemy_data
{
position_data location;
enemy_type_data type;
bitmap bmp;
double health;
double speed;
int path_to;
} enemy_data;
typedef struct enemy_data_array
{
int size;
enemy_data *data;
} enemy_data_array;
Here is the function to add an element to the array:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
enemies->size++;
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
if (new_array) //if realloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
And here is my function call and variable declaration in the main procedure:
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
add_enemy(&enemies);
}
Why isn't this working?
You invoked undefined behavior by passing indeterminate value enemies->data in uninitialized variable having automatic storage duration. Initialize it before using add_enemy().
int main()
{
path_data my_path[41];
enemy_data_array enemies;
enemies.size = 0;
enemies.data = 0; /* add this line */
add_enemy(&enemies);
}
0 is a null pointer constant and can safely be converted to pointer NULL. Unlike NULL, 0 will work without including any headers. Of course you can use enemies.data = NULL; with proper header included.
#2501's explanation is completely correct. Another solution is to change your implementation of add_enemy() to something like this:
void add_enemy(enemy_data_array *enemies)
{
enemy_data *new_array;
// check if size was non-zero
if (enemies->size++)
{
new_array = (enemy_data *)realloc(enemies->data, sizeof(enemy_data) * enemies->size);
}
// start new allocation
else
{
new_array = (enemy_data *)alloc(sizeof(enemy_data) * enemies->size);
}
if (new_array) //if (re)alloc fails (ie out of memory) it will return null
{
enemies->data = new_array;
// enemies->data[enemies->size - 1] = read_enemy_data();
printf("Enemy added successfully!\n");
}
else
{
printf("FAILED. Out of Memory!\n");
enemies->size--;
}
}
If fails because you haven't cleared the content of "enemies". Since it is a stack variable, it will contain whatever garbage data is on the stack.
set enemies.data to NULL in the main function and try it again.
I have been learning how to use Unix functions to program in C so that I can program Semaphore functionality by scratch (without pthreads), but I am currently stuck. The man pages told me to include particular header files to use functions of interest (such as malloc, tsleep, wakeup, etc.), but when I try to run my program with the headers and method calls, I receive the following errors:
/tmp//ccg29960.o: In function `allocate_semaphore':
/tmp//ccg29960.o(.text+0x28d): undefined reference to `simple_lock_init'
/tmp//ccg29960.o: In function `down_semaphore':
/tmp//ccg29960.o(.text+0x2fb): undefined reference to `tsleep'
/tmp//ccg29960.o: In function `up_semaphore':
/tmp//ccg29960.o(.text+0x3b5): undefined reference to `wakeup'
/tmp//ccg29960.o: In function `free_semaphore':
/tmp//ccg29960.o(.text+0x43b): undefined reference to `simple_lock'
/tmp//ccg29960.o(.text+0x4af): undefined reference to `simple_unlock'
collect2: ld returned 1 exit status
The relevant code is below:
//#include <stdio.h>
//#include <stdlib.h>
#include <sys/errno.h>
#include <sys/queue.h>
//#include <sys/time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/lock.h>
struct entry
{
pid_t id;
SIMPLEQ_ENTRY(entry) next;
} *np;
typedef struct
{
const char* name;
pid_t process;
pid_t p_process; //parent process
int count;
SIMPLEQ_HEAD(queuehead,entry) head;
struct simplelock *slock;
} named_semaphore;
named_semaphore* s_list[64];
int num_semaphores = 0;
int main()
{
//lockinit(0, 0, 0,0, 0);
printf("Hello world\n");
return 0;
}
//... irrelevant code elided
int allocate_semaphore( const char* name, int initial_count )
{
int num_elements, i;
named_semaphore *new_s;
//perform initial checks before creating a new semaphore
//make sure the given name is an acceptable length
num_elements = sizeof(name) / sizeof(*name);
if ( num_elements > 32 )
{
return ENAMETOOLONG;
}
//make sure the given name is unique to this process
for (i = 0; i < num_semaphores; i++)
{
if (s_list[i]->process == getpid() && strcmp(s_list[i]->name, name))
{
return EEXIST;
}
}
//make sure there are no more than 64 semaphores active
if (num_semaphores >= 64)
{
return ENOMEM;
}
//create a new semaphore and add it to the collection
new_s = (named_semaphore*) malloc(sizeof(named_semaphore), 0, 0);
new_s->name = name;
new_s->process = getpid();
new_s->p_process = getppid();
new_s->count = initial_count;
s_list[num_semaphores] = new_s;
++num_semaphores;
//initialize the waiting queue
SIMPLEQ_INIT( &(new_s->head) );
//initialize its lock
simple_lock_init( new_s->slock );
//need to handle negative initial_count somehow
return (0);
}
int down_semaphore( const char* name )
{
named_semaphore* s;
s = getSemaphore( name );
if (s == NULL)
{
return (ENOENT);
}
s->count = (s->count) - 1;
if (s->count < 0)
{
//put process to sleep
tsleep(getpid(), getpriority(), 0, 0);
//add process to waiting queue
np = (struct entry *) malloc(sizeof(struct entry ));
np->id = getpid();
SIMPLEQ_INSERT_TAIL( &(s->head), np, next );
}
return 0;
}
int up_semaphore ( const char* name )
{
named_semaphore* s;
s = getSemaphore( name );
if ( s == NULL )
{
return (ENOENT);
}
s->count = (s->count) + 1;
if (s->count <= 0)
{
//wakeup longest waiting process
wakeup( (SIMPLEQ_FIRST( &(s->head) ))->id );
//remove process from waiting queue
SIMPLEQ_REMOVE_HEAD( &(s->head), np, next );
free( np );
}
return 0;
}
int free_semaphore( const char* name )
{
named_semaphore* s;
s = getSemaphore( name );
if ( s == NULL )
{
return (ENOENT);
}
simple_lock( s->slock );
while ( (np = SIMPLEQ_FIRST( &(s->head) ) ) != NULL )
{
//wakeup the process and return ECONNABORTED
//wakeup( getSemaphore( np->id ) );
SIMPLEQ_REMOVE_HEAD( &(s->head), np, next );
free( np );
}
free( s );
simple_unlock( s->slock );
}
I am not done modifying/fixing the logic of my overall program (for example, the lock()ing only happens in 1/3 of the intended methods), but it would be wonderful to understand why I am getting my current error so that I know how to fix similar ones in the future.
To me it seems like the methods do not recognize their header files or that I am missing a required piece of information so that the two can communicate.
To fix the errors, I've tried rearranging and commenting out the listed header files and also renaming the method calls in uppercase letters like they were presented in the header file documentation.
Any help or insight is appreciated, and thank you in advance!
The man pages you read... those were section 9, weren't they? Section 9 is for kernel programming. You can't call those functions unless your code is in the kernel.
The revelant code may be found here: http://pastebin.com/VbhtQckm
The problem is at line
85. pthread_mutex_lock(ID_retrieval_pool->info->lock);
I'm running the server and it's getting stuck at lock. The memory is allocated, I'm initializing the mutex and it's the only thread who's owning that shared memory.
I did debug with GDB and Valgrind using helgrind tool but did not find any clue.
Possible problems which think may cause this:
mutex is not being initialized (I'm using a block is shared memory which I'm initializing as a mutex);
deadlock? in the man page https://www.sourceware.org/pthreads-
win32/manual/pthread_mutex_init.html says this can cause this;
Please note that this code is for learning purpose.
Edit, the code is:
// common_header.h + common_header.c
#ifndef DATA_TYPES_H
#define DATA_TYPES_H
#include <pthread.h>
#include <errno.h>
#define RETREIVE_ID_KEY 1
typedef enum {
SHM_State_None,
SHM_State_ID_Available,
SHM_State_ID_Not_Available,
} SHM_State;
typedef struct {
pthread_mutex_t *lock; // locked if any thread is modifying data
SHM_State state;
} data_state;
typedef int shmid_t;
typedef struct data_pool {
data_state *info;
shmid_t shm_id;
} data_pool;
// other data structures
extern data_state * data_state_initialize_by_setting_address(void *address)
{
data_state *data = (data_state *)address;
data->lock = (pthread_mutex_t *)address;
pthread_mutex_init(data->lock, NULL);
data->state = SHM_State_None;
return data;
}
extern data_pool * data_pool_initialize_by_setting_address(void *address)
{
data_pool *data = (data_pool *)address;
data->info = data_state_initialize_by_setting_address(address);
data->shm_id = 0; // invalid though, the structure's client has to set a valid one
return data;
}
// other initialization functions
#endif // DATA_TYPES_H
///----------------------------------------------------------------------------------------\\\
// main.c -- Server
#include "common_header.h"
#define SHM_INVALID_ADDRESS (void *)-1
#define SHMGET_RW_FLAGS 0666
#define SHMAT_RW_FLAGS 0
bool initialize_data();
static data_pool *ID_retrieval_pool = NULL;
int main(int argc, char *argv[])
{
if (!initialize_data()) {
return EXIT_FAILURE;
}
// Do other stuff
return EXIT_SUCCESS;
}
bool initialize_data()
{
// some irrelevant initialization code
shmid_t shm_ID = shmget(RETREIVE_ID_KEY,
sizeof(data_pool),
IPC_CREAT | SHMGET_RW_FLAGS);
void *shm_address = shmat(shm_ID, NULL, SHMAT_RW_FLAGS);
if (shm_address == SHM_INVALID_ADDRESS) {
return false;
}
ID_retrieval_pool = data_pool_initialize_by_setting_address(shm_address);
pthread_mutex_lock(ID_retrieval_pool->info->lock);
ID_retrieval_pool->shm_id = get_shared_ID();
ID_retrieval_pool->info->state = SHM_State_ID_Available;
pthread_mutex_unlock(ID_retrieval_pool->info->lock);
// other initialization code
return true;
}
You have an interesting and incorrect way of initializing the mutex:
data->lock = (pthread_mutex_t *)address; /* address == &data */
pthread_mutex_init(data->lock, NULL);
In your code address is the address of the outer struct: this does not actually allocate a usable block of memory.
I suggest you just make the mutex non-pointer and then initialize it:
/* In the struct. */
pthread_mutex_t lock;
/* In your function. */
pthread_mutex_init(&data->lock, NULL);
Note: Fixed (decription at bottom)
For some reason the following code:
(*p_to_array)[m_p->number_of_match_positions] = (*p_to_temp_array)[k];
where the types are:
match_pos_t (*p_to_array)[];
match_pos_t (*p_to_temp_array)[];
int number_of_match_positions;
int k;
BTW: match_pos_t is a struct:
typedef struct match_pos
{
char* string;
long match_position;
}match_pos_t;
causes a 'syntax error before '(' error'
This error does not occur if this code replaced with other code.
Could someone give me an idea of why this is causing a syntax error, and how I should fix this problem?
Entire relevant code:
typedef struct match_pos
{
char* string;
long match_position;
}match_pos_t;
typedef struct match_positions
{
int number_of_match_positions;
match_pos_t (*match_positions)[];
}match_positions_t;
typedef struct search_terms
{
int number_of_search_terms;
char* search_terms[];
}search_terms_t;
int BMH_string_search(char* search_string, char* file_string, match_positions_t* match_positions)
{
return 0;
}
int determine_match_pos(search_terms_t** s_terms, char* file, match_positions_t* m_p)
{
int i,j,k;
match_positions_t* temp_m_p;
i=0;
/* s_terms is a null terminated data structure */
while((*s_terms+i) != NULL)
{
for(j=0; j<(*s_terms+i)->number_of_search_terms; j++)
{
/* search for the string positions */
BMH_string_search((*s_terms+i)->search_terms[j], file, temp_m_p);
/* load out search positions into the return array */
if(temp_m_p->number_of_match_positions != 0)
{
int total_m_ps = m_p->number_of_match_positions + temp_m_p->number_of_match_positions;
m_p->match_positions = (match_pos_t (*)[])realloc(m_p->match_positions, sizeof(match_pos_t)*total_m_ps);
k = 0;
for( ; m_p->number_of_match_positions<total_m_ps; m_p->number_of_match_positions++)
{
(*(m_p->match_positions))[m_p->number_of_match_positions] = (*(temp_m_p->match_positions))[k];
k++;
}
}
free(temp_m_p);
}
i++;
}
return 0;
}
It appears I have been rather stupid. An extra set of parenthesis around the values being referenced does the trick (question code has been updated with fix):
Original:
(m_p->*match_positions)[m_p->number_of_match_positions] = (temp_m_p->*match_positions)[k];
Fixed:
(*(m_p->match_positions))[m_p->number_of_match_positions] = (*(temp_m_p->match_positions))[k];
If anyone has an explanation, though, about why the first is incorrect, rather than the second, it would be nice to hear though, as I thought that
object->*object2
was the same as
*(object->object2)
Is this correct or is there some c definitions that I am missing out on here?
I thought that object->*object2 was the same as *(object->object2)
No, in C, the . and -> operators expect an identifier as their right operand. The .* and ->* operators don't exist in C, you have to spell out *(structure.member) or *(structure_ptr->member) manually.